【拓扑排序或差分约束】Guess UVALive - 4255

题目连接:https://cn.vjudge.net/contest/209473#problem/Bspa

 

题目大意:对于n个数字,给出sum[j]-sum[i](sum表示前缀和)的符号(正负零),求一组n个数的的可行解(n个数都在-10——10之间)【保证必定有解】.net

 

解题思路:code

第一反应!差分约束!blog

差分约束是用来求解不等式组的合理解的,用在此题上恰好,把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.排序

差分约束以后会在另外一个专题里讲到,会此方法的同窗已经能够建图跑最短路了,不会此方法的同窗建议选择第二种方法拓扑排序。【可是推荐差分约束,由于感受比拓排简单】get

 

后来和别的同窗交流讨论,才知道这道题正解,或者说官方解是拓扑排序。string

把大小关系改为单向连边,好比本鶸的丑代码就是把大的前缀和引出一条边指向小的前缀和。io

特殊点在于等于零的处理,想了半个小时(好弱啊),想到一个很丑陋的方法,就是把两个相等的点的大小关系彻底复制。也就是说若是sum[A]==sum[B],那么全部链接A却没有链接B的边,全加在B上,全部链接B没有链接A的边,全加在A上,不管方向。class

第二个特殊点在于控制n个数的大小,若是选择差分约束只须要把上限值改为10就好了,对于拓排,我就想了个丑方法,把最大的前缀和赋为10*n,往下每一层减1,因为题目保证必定有解,因此不会出现问题。test

 

下面放代码:

 

差分约束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 }
相关文章
相关标签/搜索