SCOI 2012 奇怪的游戲


題目:http://61.187.179.132/JudgeOnline/problem.php?id=2756

Description

Blinker最近喜歡上一個奇怪的游戲。 
這個游戲在一個 N*M 的棋盤上玩,每個格子有一個數。每次 Blinker 會選擇兩個相鄰
的格子,並使這兩個數都加上 1。 
現在 Blinker 想知道最少多少次能使棋盤上的數都變成同一個數,如果永遠不能變成同
一個數則輸出-1。 

Input

輸入的第一行是一個整數T,表示輸入數據有T輪游戲組成。 
每輪游戲的第一行有兩個整數N和M, 分別代表棋盤的行數和列數。 
接下來有N行,每行 M個數。 

Output


  對於每個游戲輸出最少能使游戲結束的次數,如果永遠不能變成同一個數則輸出-1。

Sample Input

2
2 2
1 2
2 3
3 3
1 2 3
2 3 4
4 3 2

Sample Output

2
-1

HINT

 

【數據范圍】 

    對於30%的數據,保證  T<=10,1<=N,M<=8 

對於100%的數據,保證  T<=10,1<=N,M<=40,所有數為正整數且小於1000000000 

 

題解:

  給格子黑白染色后我們會發現,每次必定是把一個黑格子和一個白格子的值加1,那么就可以把兩邊給分開了。

 

  設白格子有num1個,數值和為sum1,黑格子有num2 個,數值和為sum2,設所有數最后都變成了x,那么有x*num1-sum1=x*num2-sum2,解之可得x=(sum1-sum2)/(num1-num2),當num1=num2即有偶數個格子時,此方程無意義,所以先說num1!=num2的情況。

 

  num1!=num2時,解出一個x,由於始終是把兩個格子的值加1,所以若有解,x不可能小於所有值中的最大值且x必須是個整數,那么這樣就只需檢驗當x滿足上述兩個條件時,是否可行即可了。

 

  num1=num2時,如果說都變成x可以實現,那么都變成x+1也能實現(做法是黑白格子兩兩配對后加1),所以可以二分最后變成的那個數即可(所操作的次數與x的大小是正相關的)。

 

  那么現在只需要檢驗當能否所有數都變成x,自然而然地就想到網絡流了。總源向每個白格子連邊,每個黑格子向總匯連邊,流量為x減去該格子本來的權值,然后相鄰的黑白格子連流量為無限大的邊,求個最大流max_flow,並且提前算出若該方案可行需要多少步step,如果max_flow=step,則說明這是一個可行解,否則為不可行。

 

  網絡流建議寫非遞歸的,遞歸的跑起來有點慢(雖說應該不會有太大影響的,但我的遞歸的T了),然后左右界稍微卡好一點,不然也容易T。

 

  考試的時候已經把方法都想出來了,可是不知道又哪里寫錯了,再次崩掉。唉,還得努力攢RP啊……………………

 

View Code
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<queue>
 5  
 6 using namespace std;  7  
 8 const int maxw=41;  9 const int maxn=1800;  10 const int maxm=100000;  11 const long long INF=123456789876ll;  12  
 13 int n,m,en,d[maxn],s,e,stack[maxn];  14  
 15 long long map[maxw][maxw];  16  
 17 queue<int> que;  18  
 19 struct edge  20 {  21     int e;  22     long long f;  23     edge *next,*op;  24 }*v[maxn],ed[maxm],*p[maxn],*fe[maxn];  25  
 26 void add_edge(int s,int e,long long f)  27 {  28     en++;  29     ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->f=f;  30     en++;  31     ed[en].next=v[e];v[e]=ed+en;v[e]->e=s;v[e]->f=0;  32     v[s]->op=v[e];v[e]->op=v[s];  33 }  34  
 35 int get(int x,int y)  36 {  37     return (x-1)*m+y;  38 }  39  
 40 void get_add(int x,int y)  41 {  42     if (x>1) add_edge(get(x,y),get(x-1,y),INF);  43     if (x<n) add_edge(get(x,y),get(x+1,y),INF);  44     if (y>1) add_edge(get(x,y),get(x,y-1),INF);  45     if (y<m) add_edge(get(x,y),get(x,y+1),INF);  46 }  47  
 48 bool bfs()  49 {  50     memset(d,-1,sizeof(d));  51     d[s]=0;  52  que.push(s);  53     while (que.size())  54  {  55         int now=que.front();  56  que.pop();  57         for (edge *e=v[now];e;e=e->next)  58             if (e->f && d[e->e]==-1)  59  {  60                 d[e->e]=d[now]+1;  61                 que.push(e->e);  62  }  63  }  64  
 65     return d[e]!=-1;  66 }  67  
 68 long long dfs(int now,long long cur_flow)  69 {  70     if (now==e) return cur_flow;  71     long long rest=cur_flow;  72     for (edge *e=v[now];e;e=e->next)  73         if (e->f && d[e->e]==d[now]+1)  74  {  75             long long new_flow=dfs(e->e,min(rest,e->f));  76             e->f-=new_flow;  77             e->op->f+=new_flow;  78             rest-=new_flow;  79  }  80     return cur_flow-rest;  81 }  82  
 83 long long agument()  84 {  85     int now,next,stop;  86     long long delta,ans=0;  87     for (int a=s;a<=e;a++)  88         p[a]=v[a];  89     stack[stop=1]=s;  90     int t=e;  91     while (stop>0)  92  {  93         now=stack[stop];  94         if (now!=t)  95  {  96             for (;p[now];p[now]=p[now]->next)  97                 if ((p[now]->f) && (d[now]+1==d[next=p[now]->e])) break;  98             if (p[now])  99  { 100                 stack[++stop]=next; 101                 fe[stop]=p[now]; 102  } 103             else
104  { 105                 stop--; 106                 d[now]=-1; 107  } 108  } 109         else
110  { 111             delta=INF; 112             for (int a=stop;a>=2;a--) 113                 if (fe[a]->f<delta) delta=fe[a]->f; 114             ans+=delta; 115             for (int a=stop;a>=2;a--) 116  { 117                 fe[a]->f-=delta; 118                 fe[a]->op->f+=delta; 119                 if (fe[a]->f==0) stop=a-1; 120  } 121  } 122  } 123     return ans; 124 } 125  
126 long long dinic() 127 { 128     long long ans=0; 129     while (bfs()) 130         ans+=agument(); 131     return ans; 132 } 133  
134 bool check(long long x) 135 { 136     en=0; 137     memset(v,0,sizeof(v)); 138     s=0; 139     e=n*m+1; 140     long long flow=0; 141     for (int a=1;a<=n;a++) 142         for (int b=1;b<=m;b++) 143  { 144             if ((a+b)%2==0) 145  { 146                 add_edge(s,get(a,b),x-map[a][b]); 147  get_add(a,b); 148  } 149             else add_edge(get(a,b),e,x-map[a][b]); 150             flow+=x-map[a][b]; 151  } 152     long long ans=dinic(); 153     if (ans*2!=flow) return false; 154     else return true; 155 } 156  
157 long long gettime(long long x) 158 { 159     long long ans=0; 160     for (int a=1;a<=n;a++) 161         for (int b=1;b<=m;b++) 162             ans+=x-map[a][b]; 163     return ans>>1; 164 } 165  
166 int main() 167 { 168     freopen("game.in","r",stdin); 169     freopen("game.out","w",stdout); 170  
171     int t; 172     scanf("%d",&t); 173     for (int z=1;z<=t;z++) 174  { 175         scanf("%d%d",&n,&m); 176         int num1=0,num2=0; 177         long long sum1=0,sum2=0; 178         long long max_v=0; 179         for (int a=1;a<=n;a++) 180             for (int b=1;b<=m;b++) 181  { 182                 scanf("%lld",&map[a][b]); 183                 if ((a+b)%2==0) 184  { 185                     num1++; 186                     sum1+=map[a][b]; 187  } 188                 else
189  { 190                     num2++; 191                     sum2+=map[a][b]; 192  } 193                 max_v=max(max_v,map[a][b]); 194  } 195         if (num1!=num2) 196  { 197             if ((sum1-sum2) % (num1-num2)!=0) 198  { 199                 printf("-1\n"); 200                 continue; 201  } 202             else
203  { 204                 long long x=(sum1-sum2)/(num1-num2); 205                 if (x<max_v) 206  { 207                     printf("-1\n"); 208                     continue; 209  } 210                 if (check(x)) printf("%lld\n",gettime(x)); 211                 else printf("-1\n"); 212  } 213  } 214         else
215  { 216             long long l=max_v-1,r=INF; 217             while (l+1!=r) 218  { 219                 long long m=(l+r)>>1; 220                 if (check(m)) r=m; 221                 else l=m; 222  } 223             if (check(r)) printf("%lld\n",gettime(r)); 224             else printf("-1\n"); 225  } 226  } 227  
228     return 0; 229 }

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM