3 3
1 2
1 3
2 3
3 2
1 2
2 3
0
1
0
/* 无向图存在欧拉回路的充要条件 一个无向图存在欧拉回路,当且仅当该图所有顶点度数都为偶数,且该图是连通图。 有向图存在欧拉回路的充要条件 一个有向图存在欧拉回路,所有顶点的入度等于出度且该图是连通图。 */ #include<iostream> #include<string.h> using namespace std; struct node{ int st; int en; }a[1000000]; int root[1005]; int pre[1005]; int dushu[1005]; int find(int x) { int r=x; while(pre[r]!=r) r=pre[r]; int i=x,j; while(pre[i]!=r) { j=pre[i]; pre[i]=r; i=j; } return r; } int main() { int n,m,ans,flag1,flag2; while(cin>>n>>m&&n) { memset(dushu,0,sizeof(dushu)); memset(root,0,sizeof(root)); ans=0; flag1=0; flag2=1; for(int i=1;i<=n;i++) pre[i]=i;//初始化每个点的上级是他自己 for(int i=1;i<=m;i++) { cin>>a[i].st>>a[i].en; dushu[a[i].st]++;//度数增加1 dushu[a[i].en]++;//度数增加1 int fx=find(a[i].st); int fy=find(a[i].en); if(fx!=fy) { pre[fx]=fy; } } for(int i=1;i<=n;i++) root[find(i)]=1; for(int i=1;i<=n;i++) { if(root[i]) ans++; } if(ans==1) flag1=1; for(int i=1;i<=n;i++) { if(dushu[i]%2!=0) { flag2=0; break; } } if(flag1==1&&flag2==1) cout<<"1"<<endl; else cout<<"0"<<endl; } return 0; }
3
1 2 1 0
1 3 2 0
2 3 4 0
3
1 2 1 0
1 3 2 0
2 3 4 1
3
1 2 1 0
1 3 2 1
2 3 4 1
0
3
1
0
/* 最小生成树能够保证整个拓扑图的所有路径之和最小,但不能保证任意两点之间是最短路径。 最短路径是从一点出发,到达目的地的路径最小。 */ #include<iostream> #include<string.h> #include<algorithm> using namespace std; int pre[105]; struct node{ int st; int en; int cost; int state; }a[10000]; int find(int x)//找到x的上级 { int r=x; while(pre[r]!=r)//如果r的上级不是r,即r不是根节点 r=pre[r];//r是根节点 /////////////路径压缩,将所有下属的上级都设置为根节点 int i=x,j; while(pre[i]!=r) { j=pre[i];//记录i的上级 pre[i]=r;//将r的上级设置为根节点 i=j;//对上级继续处理 } ///////////////////////// return r;//返回根节点 } int cmp(struct node a,struct node b) { return a.cost<b.cost?1:0; } int main() { int sum,n,count; while(cin>>n&&n) { for(int i=1;i<=n*(n-1)/2;i++) { cin>>a[i].st>>a[i].en>>a[i].cost>>a[i].state; if(a[i].state==1) a[i].cost=0;//将修好的路费用当做0,然后进行最小生成树算法 } for(int i=1;i<=n;i++)//初始化,将n个村庄看成n个独立的分支,每个的祖先就是自己 pre[i]=i; sort(a+1,a+1+n*(n-1)/2,cmp);//将所有的边从小到大排序 sum=0; count=0; for(int i=1;i<=n*(n-1)/2;i++) { //合并函数 int fx = find(a[i].st); int fy = find(a[i].en); if (fx != fy){ pre[fx] = fy; sum += a[i].cost; count++; } } if(count==n-1)//说明所有的顶点都已经连接了 ,count为连接的边数,说明畅通 cout<<sum<<endl; } return 0; }
首先列出词典中不超过100000条不同的魔咒词条,每条格式为:
[魔咒] 对应功能
其中“魔咒”和“对应功能”分别为长度不超过20和80的字符串,字符串中保证不包含字符“[”和“]”,且“]”和后面的字符串之间有且仅有一个空格。词典最后一行以“@END@”结束,这一行不属于词典中的词条。
词典之后的一行包含正整数N(<=1000),随后是N个测试用例。每个测试用例占一行,或者给出“[魔咒]”,或者给出“对应功能”。
[expelliarmus] the disarming charm
[rictusempra] send a jet of silver light to hit the enemy
[tarantallegra] control the movement of one's legs
[serpensortia] shoot a snake out of the end of one's wand
[lumos] light the wand
[obliviate] the memory charm
[expecto patronum] send a Patronus to the dementors
[accio] the summoning charm
@END@
4
[lumos]
the summoning charm
[arha]
take me to the sky
light the wand
accio
what?
what?
/* 将魔咒和功能存储并且按照字母顺序从大到小排序,然后利用二分搜索查找,此题重要是查找效率,故选择二分查找 */ #include <stdio.h> #include<stdlib.h> #include<string.h> struct node{ char wo[100]; char ex[100]; }a[10000],b[10000]; int cmp(const void *a,const void *b) { return strcmp((*(struct node*)a).wo,(*(struct node*)b).wo); } int cmp1(const void *a,const void *b) { return strcmp((*(struct node*)a).ex,(*(struct node*)b).ex); } int main() { char s[100];//每次输入一行词条 int i,k,j; int m,low,high,ans; int n; char c[100];//测试样例 k=0; while(gets(s)&&strcmp(s,"@END@")) { i=1; j=0; while(s[i]!=']')//将魔咒存储好 { a[k].wo[j]=s[i]; b[k].wo[j]=s[i]; j++; i++; } a[k].wo[j+1]='\0'; //作为字符数组的结尾符不要忽略 b[k].wo[j+1]='\0'; i=i+2; j=0; while(s[i]!='\0')//开始存储功能 ,结尾符在此出可以作为判断条件 { a[k].ex[j]=s[i]; b[k].ex[j]=s[i]; j++; i++; } a[k].ex[j+1]='\0'; //作为字符数组的结尾符不要忽略 b[k].ex[j+1]='\0'; k++; } //输入词条完毕; 开始测试。 qsort(a,k,sizeof(a[0]),cmp);//存储对魔咒排序的结果 qsort(b,k,sizeof(b[0]),cmp1);//存储对功能排序的结果 scanf("%d",&n); getchar();//防止将回车符读成字符串 while(n--) { low=0; high=k-1; ans=-1; gets(c); if(c[0]=='[')//表示输入的是魔咒 {// 这部分是为了去除[] int len; len=strlen(c); for(i=0;i<len-2;i++) c[i]=c[i+1]; c[i]='\0'; // while(low<=high) { m=(low+high)/2; if(strcmp(c,a[m].wo)<0) high=m-1; else if(strcmp(c,a[m].wo)>0) low=m+1; else { ans=m; break; } } if(ans==-1) printf("what?\n"); else printf("%s\n",a[ans].ex); } else//表示输入的是功能 { while(low<=high) { m=(low+high)/2; if(strcmp(c,b[m].ex)<0) high=m-1; else if(strcmp(c,b[m].ex)>0) low=m+1; else { ans=m; break; } } if(ans==-1) printf("what?\n"); else printf("%s\n",b[ans].wo); } } return 0; }
每个测试用例的输出占一行,输出最大快乐度。
3
6 3 3
3 2 2
4 1 3
4
5 1 1
10 2 3
6 1 2
3 1 1
-1
7
16
/* *这个还是0-1背包问题. *思路: 首先对所有的bg按照发起人必须离开的时间从小到大排序 *dp[i]表示发起人必须在i点离开时能获得的最大欢乐度,每当加入一个新的bg时, *这个bg要么会增加晚会的欢乐度,要么不会增加,这两种情况获得的欢乐度分别是dp[i - 要加入的bg的持续时间],上一个dp[i]; *每次计算完dp[i],把dp[i + 1]到dp[sum](所有bg的最大离开时间)标记为dp[i],因为走了之后欢乐度不会变化了。 */ #include <cstdio> #include <algorithm> #include<math.h> #include <string.h> using namespace std; struct E{ int a, b, c; }a[31]; int cmp(struct E a,struct E b) { return a.c<b.c; } int dp[50]; int main(){ int sum, n; while(~scanf("%d", &n) && n >= 0){ sum = 0; for(int i = 1; i <= n; i++){ scanf("%d%d%d", &a[i].a, &a[i].b, &a[i].c); if(sum < a[i].c) sum = a[i].c;//获得最晚的发起人离开时间 } memset(dp, 0, sizeof(dp)); sort(a + 1, a + n + 1,cmp); for(int i = 1; i <= n; i++){//依次决定n个活动参加或者不参加 for(int j = a[i].c; j >= a[i].b; j--) dp[j] = max(dp[j], dp[j - a[i].b] + a[i].a);//dp[i]表示发起人必须在i点离开时能获得的最大欢乐度 for(int j = a[i].c + 1; j <= sum; j++) dp[j] = dp[a[i].c];//对于在最晚的发起人离开时间之前走的人,已经离开后他的欢乐度就不会再变化 } printf("%d\n", dp[sum]); } return 0; }