题目链接:https://cn.vjudge.net/contest/209473#problem/B
题目大意:对于n个数字,给出sum[j]-sum[i](sum表示前缀和)的符号(正负零),求一组n个数的的可行解(n个数都在-10——10之间)【保证一定有解】
解题思路:
第一反应!差分约束!
差分约束是用来求解不等式组的合理解的,用在此题上刚好,把sum[i]-sum[j]>0转化为sum[i]-sum[j]>=-1,小于零同理。把sum[i]-sum[j]==0转化为sum[i]-sum[j]>=0,sum[j]-sum[i]>=0.
差分约束之后会在另一个专题里讲到,会此方法的同学已经可以建图跑最短路了,不会此方法的同学建议选择第二种方法拓扑排序。【但是推荐差分约束,因为感觉比拓排简单】
后来和别的同学交流讨论,才知道这道题正解,或者说官方解是拓扑排序。
把大小关系改成单向连边,比如本鶸的丑代码就是把大的前缀和引出一条边指向小的前缀和。
特殊点在于等于零的处理,想了半个小时(好弱啊),想到一个很丑陋的方法,就是把两个相等的点的大小关系完全复制。也就是说如果sum[A]==sum[B],那么所有连接A却没有连接B的边,全加在B上,所有连接B没有连接A的边,全加在A上,无论方向。
第二个特殊点在于控制n个数的大小,如果选择差分约束只需要把上限值改成10就行了,对于拓排,我就想了个丑方法,把最大的前缀和赋为10*n,往下每一层减1,由于题目保证一定有解,所以不会出现问题。
下面放代码:
差分约束6msAC代码:
1 /* by Lstg */ 2 /* 2018-01-27 15:32:28 */ 3 4 #include<stdio.h> 5 #define inf 102000000 6 7 int map[105][105]; 8 9 10 int main(){ 11 12 int T,i,j,n,k; 13 char t; 14 scanf("%d",&T); 15 while(T--){ 16 17 scanf("%d",&n); 18 getchar(); 19 for(i=0;i<=n+1;i++) 20 for(j=0;j<=n+1;j++) 21 if(i!=j)map[i][j]=inf; 22 for(i=1;i<=n;i++) 23 for(j=i;j<=n;j++){ 24 t=getchar(); 25 if(t==‘+‘)map[j][i-1]=-1; 26 else if(t==‘-‘)map[i-1][j]=-1; 27 else 28 map[i-1][j]=map[j][i-1]=0; 29 30 } 31 for(i=0;i<=n;i++) 32 map[n+1][i]=10; 33 n++; 34 for(k=0;k<=n;k++) 35 for(i=0;i<=n;i++) 36 for(j=0;j<=n;j++) 37 if(map[i][k]+map[k][j]<map[i][j]) 38 map[i][j]=map[i][k]+map[k][j]; 39 for(i=1;i<n;i++) 40 printf("%d ",map[n][i]-map[n][i-1]); 41 putchar(10); 42 } 43 return 0; 44 }
拓扑排序6msAC代码:
1 /* by Lstg */ 2 /* 2018-03-04 00:11:12 */ 3 4 5 #include<stdio.h> 6 #include<string.h> 7 8 int sum[105],g[105][105],du[105],stk[105],n; 9 10 void _getans(){ 11 12 int i,top=0,p; 13 for(i=0;i<=n;i++) 14 if(!du[i]){ 15 stk[++top]=i; 16 sum[i]=10*n; 17 } 18 while(top){ 19 p=stk[top--]; 20 for(i=0;i<=n;i++) 21 if(g[p][i]){ 22 du[i]--; 23 if(!du[i]){ 24 sum[i]=sum[p]-1; 25 stk[++top]=i; 26 } 27 } 28 } 29 } 30 31 int main(){ 32 33 34 int T,i,j,k; 35 char ch[105]; 36 37 scanf("%d",&T); 38 while(T--){ 39 40 memset(du,0,sizeof(du)); 41 memset(g,0,sizeof(g)); 42 memset(sum,0,sizeof(sum)); 43 scanf("%d",&n); 44 45 scanf("%s",ch); 46 k=0; 47 for(i=0;i<n;i++) 48 for(j=i+1;j<=n;j++){ 49 if(ch[k]==‘+‘){ 50 g[j][i]=true; 51 du[i]++; 52 } 53 if(ch[k]==‘-‘){ 54 g[i][j]=true; 55 du[j]++; 56 } 57 k++; 58 } 59 k=0; 60 for(i=0;i<n;i++) 61 for(j=i+1;j<=n;j++) 62 if(ch[k++]==‘0‘) 63 for(int a=0;a<=n;a++){ 64 if(!g[i][a]&&g[j][a]){ 65 g[i][a]=true; 66 du[a]++; 67 } 68 if(!g[j][a]&&g[i][a]){ 69 g[j][a]=true; 70 du[a]++; 71 } 72 if(!g[a][i]&&g[a][j]){ 73 g[a][i]=true; 74 du[i]++; 75 } 76 if(!g[a][j]&&g[a][i]){ 77 g[a][j]=true; 78 du[j]++; 79 } 80 } 81 _getans(); 82 83 for(i=1;i<=n;i++) 84 85 printf("%d ",sum[i]-sum[i-1]); 86 putchar(10); 87 } 88 return 0; 89 }