題目連接: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 }