分考场
问题描述
n个人参加某项特殊考试。
为了公平,要求任何两个认识的人不能分在同一个考场。
求是少需要分几个考场才能满足条件。
输入格式
第一行,一个整数n(1<n<100),表示参加考试的人数。
第二行,一个整数m,表示接下来有m行数据
以下m行每行的格式为:两个整数a,b,用空格分开 (1<=a,b<=n) 表示第a个人与第b个人认识。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e2+2;
int g[MAXN][MAXN];//用邻接矩阵存储关系
int room[MAXN][MAXN]; //room[i][j]表示当前i号教室第j个人为room[i][j]
int MIN ;//优化一:当前状态下的最小教室
int n,m;//点数,边数
void dfs(int v,int c){
if(c>=MIN)return;//剪枝
if(v>n){
MIN=MIN>c?c:MIN;
return;
}
for(int i=1;i<=c;++i){
//循环判断每个教室的每个人是否与v有关系
int k =0;
while(room[i][k]&&g[v][room[i][k]]==0){
//如果当前教室i,第k个人的编号room[i][k]与v有关系退出
k++;
}
if(room[i][k]==0){
//有当前教室i的所有人无关系,可加入教室
room[i][k]=v;
dfs(v+1,c);//把v+1加入到教室
room[i][k]=0;//回溯
}
}
room[c+1][0]=v;//或者新开一间教室放该v,(注不是所有教室不满足条件)
dfs(v+1,c+1);
room[c+1][0]=0;
}
int main(){
//相当于图的着色问题,用dfs
scanf("%d%d",&n,&m);
MIN = n;//易知最多教室为n
int a,b;
for(int i=0;i<m;++i){
scanf("%d%d",&a,&b);
g[a][b]=g[b][a]=1;
}
dfs(1,0);
printf("%d",MIN);
return 0;
}
翻硬币
问题描述
小明正在玩一个“翻硬币”的游戏。
桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。
比如,可能情形是:oo*oooo
如果同时翻转左边的两个硬币,则变为:oooo***oooo
现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
我们约定:把翻动相邻的两个硬币叫做一步操作,那么要求:
输入格式
两行等长的字符串,分别表示初始状态和要达到的目标状态。每行的长度<1000
#include<bits/stdc++.h>
using namespace std;
int main(){
string s1,s2;
cin>>s1>>s2;
int len = s1.size()-1;
//假设从左到右第一个不相同的的位置为i,前面就不需要再翻转,位置i的硬币也只需翻转1次,同理i+1也是
int ans=0;
for(int i=0;i<len;++i){
if(s1[i]!=s2[i]){
ans++;
s1[i+1]=s1[i+1]=='*'?'o':'*';
}
}
printf("%d",ans);
}
连号区间数
问题描述
小明这些天一直在思考这样一个奇怪而有趣的问题:
在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:
如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为R-L+1的“连续”数列,则称这个区间连号区间。
当N很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。
输入格式
第一行是一个正整数N (1 <= N <= 50000), 表示全排列的规模。
第二行是N个不同的数字Pi(1 <= Pi <= N), 表示这N个数字的某一全排列。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5e4;
int a[MAXN] ;
int main(){
//这题测试的数据量不大可以使用o(n^2)
int n;
scanf("%d",&n);
for(int i=0;i<n;++i)scanf("%d",&a[i]);
int ans = n;//一个数也包括
for(int i=0;i<n;++i){
int MIN=a[i],MAX=a[i];
for(int j=i+1;j<n;++j){
MIN = MIN>a[j]?a[j]:MIN;
MAX = MAX>a[j]?MAX:a[j];
if(MAX-MIN==j-i)ans++;
//else break; 这表示当前状态不行,加入后面的元素可以满足要求
}
}
printf("%d",ans);
}
大臣的旅费
问题描述
很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。
为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。
J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。
聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。
J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?
输入格式
输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数
城市从1开始依次编号,1号城市为首都。
接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)
每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e4;
struct Edge
{
int v,w;
Edge(int v,int w):v(v),w(w){}
Edge(){}
};
vector<Edge> g[MAXN];
int n,a,b,c;
bool visit[MAXN];
int maxWeight,p;//记录从某一节点到其他点的为最长路径为maxWeight,对应的节点为p
void dfs(int v,int weight){
visit[v]=true;
int len = g[v].size();
for(int i=0;i<len;++i){
b = g[v][i].v;
if(visit[b]==false){
weight += g[v][i].w;
if(weight>maxWeight){
maxWeight=weight;
p = b;
}
dfs(b,weight);
weight -= g[v][i].w;//需要减去到b的路径,再走另外一条路
}
}
}
int main(){
//这道题求树的最长路径,即树的直径
//通过两遍bfs(dfs)即可
scanf("%d",&n);
for(int i=1;i<n;++i){
scanf("%d%d%d",&a,&b,&c);
g[a].push_back(Edge(b,c));
g[b].push_back(Edge(a,c));
}
dfs(1,0);
maxWeight = 0;
memset(visit,0,sizeof(visit));
dfs(p,0);
printf("%d",maxWeight*10+maxWeight*(maxWeight+1)/2);
}