Codeforces Round #131 (Div. 2)
模拟一场,这场题目算是比较巧的.
a. 很简单的暴力题
b. 有点麻烦的题, 用一堆数字拼成一个最大的能被2,3,5 同时整除的数, 首先必须最后一位数字必须是0, 然后数字的总和要能被三整除 。
解法是枚举一个到两个数字,看减少这些数字能不能使数字的总和被3整除。 如果没有就输出-1
#include <stdio.h> #include <string.h> #include <string> #include <iostream> using namespace std; int mark[10]; int main() { int n; scanf("%d",&n); int sum=0; for(int i=0;i<n;i++) { int tmp; scanf("%d",&tmp); sum+=tmp; mark[tmp]++; } if(mark[0]==0) { printf("-1"); } else { if(sum%3==0) { int flag=0; for(int i=9;i>0;i--) { for(int j=mark[i];j>0;j--) { flag=1; printf("%d",i); } } if(flag==0) printf("0"); else { for(int i=0;i<mark[0];i++) printf("0"); } return 0; } int sign=0; for(int i=1;i<=9;i++) { if(mark[i]!=0) { mark[i]--; if((sum-i)%3==0) { sign=1; break; } mark[i]++; } } if(sign==1) { int flag=0; for(int i=9;i>0;i--) { for(int j=mark[i];j>0;j--) { flag=1; printf("%d",i); } } if(flag==0) printf("0"); else { for(int i=0;i<mark[0];i++) printf("0"); } return 0; } for(int i=1;i<=9;i++) { if(mark[i]==0) continue; mark[i]--; for(int j=1;j<=9;j++) { if(mark[j]!=0) { mark[j]--; if((sum-i-j)%3==0) { sign=1; break; } mark[j]++; } } if(sign==1) break; mark[i]++; } if(sign==1) { int flag=0; for(int i=9;i>0;i--) { for(int j=mark[i];j>0;j--) { flag=1; printf("%d",i); } } if(flag==0) printf("0"); else { for(int i=0;i<mark[0];i++) printf("0"); } return 0; } else printf("-1"); } return 0; }
3. 第三题很是巧妙, 也很值得一学。
题目的关键在于,边的权值 。 1->2 ,2->3 ,3->1 的权都是1,而 2->1, 3->2, 1->3 的权都为2. 由这个特殊的性质,就可以发现沿着1->2->3->1的路线走始终是最小的 因为假设你在1 你要去3 , 你可以选择1->2->3 也可以1-> 3 这两种路线花费是相同的. 而如果要去2的话1->2 就比2->1 花费要小.
所以问题就变得很简单了.
#include <stdio.h> #include <string> #include <string.h> #include <iostream> using namespace std; #define N 220 struct node { int to,next,w; }edge[N*N]; int n; int cnt,pre[N]; int mark[N],sign[N]; int in[N]; int save[N]; int mi; int sum; void add_edge(int u,int v,int w) { edge[cnt].to=v; edge[cnt].w=w; edge[cnt].next=pre[u]; pre[u]=cnt++; } void dfs(int s,int k) { for(int ii=0;ii<n;ii++) // 进行n次 for(int i=1;i<=n;i++) { if(sign[i]==0&&mark[i]==s&&in[i]==0) { k++; // 把这个电脑能打的都打完 sign[i]=1; for(int p=pre[i];p!=-1;p=edge[p].next) if(sign[edge[p].to]==0) in[edge[p].to]--; } } if(k==n) return ; sum++; if(s==3) s=1; else s++; dfs(s,k); } int main() { cnt=0; memset(pre,-1,sizeof(pre)); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&mark[i]); } for(int i=1;i<=n;i++) { int tmp; scanf("%d",&tmp); for(int j=0;j<tmp;j++) { int to; scanf("%d",&to); add_edge(to,i,1); save[i]++; } } mi=9999999; for(int i=1;i<=3;i++) { sum=0; memset(sign,0,sizeof(sign)); for(int j=1;j<=n;j++) { in[j]=save[j]; } dfs(i,0); if(sum<mi) mi=sum; } printf("%d",mi+n); return 0; }