【拓撲排序或差分約束】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 }
相關文章
相關標籤/搜索