nyoj 489
哭泣天使
時(shí)間限制:1000?ms ?|? 內(nèi)存限制:65535?KB 難度:5 描述Doctor Who乘著Tardis帶著Amy來到了一個(gè)星球,一開Tadis大門,發(fā)現(xiàn)這個(gè)星球上有個(gè)壯觀的石像群,全是一些天使石像,有的石像在哭泣,有的石像像在微笑,共有m行n列,Doctor用“音速起子”掃描了一下整個(gè)石像群,得到了每行天使中在哭泣的天使的個(gè)數(shù)。當(dāng)他與Amy在這里行走了一段時(shí)間之后,Doctor忽然想起了什么,懷疑這些石像是不是傳說中的一種黑暗生物——“哭泣天使”——一種看似石像,卻會(huì)在人不看它的時(shí)候移動(dòng),會(huì)強(qiáng)制把人送回某個(gè)過去的時(shí)間點(diǎn),并借此汲取時(shí)間能量的生物。Doctor可不想自己和Amy迷失在一個(gè)未知的時(shí)間點(diǎn)里,于是Doctor立刻用“音速起子”又掃描了整個(gè)石像群,想再看看每行的在哭泣的天使個(gè)數(shù)與剛才是否相符,但是,越急就越容易出錯(cuò),他一不小心掃描錯(cuò)了,掃描出了每列中哭泣的天使的個(gè)數(shù)。現(xiàn)在,由于音速起子的能量不足了,他不能夠再次掃描,他想根據(jù)已有的數(shù)據(jù)判斷出是否有天使改變了自己的表情,從哭泣變成不哭泣或者從不哭泣變成哭泣了。
輸入每組測(cè)試數(shù)據(jù)第一行是兩個(gè)整數(shù)m,n(0<m,n<=300)分別表示行數(shù)和列數(shù)
隨后的兩行分別有m個(gè)數(shù)和n個(gè)數(shù)分別表示對(duì)應(yīng)m行中哭泣的天使石像的個(gè)數(shù)與對(duì)應(yīng)n個(gè)列中哭泣的天使石像的個(gè)數(shù)。
如果根據(jù)已有信息無法確定石像發(fā)生了改變,則輸出Not Sure (有時(shí),你確定兩次掃描時(shí)狀態(tài)相同,但由于不確定之間是否發(fā)生過改變,故也輸出Not Sure)
Terrible
解題思路:這道題我最開始的想法就是貪心,以每一列為基準(zhǔn),用每一行的哭泣天使數(shù)去滿足這一列的哭泣天數(shù)。。可是WA啦。。。
查了下別人的思路,確實(shí)很難想到是網(wǎng)絡(luò)流,因?yàn)橐恍泻鸵涣袉为?dú)確定一個(gè)點(diǎn),所以把所有的行和列當(dāng)成點(diǎn)建邊,容量為1,再建一個(gè)源點(diǎn)s,與所有的行相連,容量為每一行哭泣天使的數(shù)量,建立一個(gè)匯點(diǎn)t,與所有的列相連,容量為相應(yīng)列哭泣天使的容量,然后求最大流,與之前得到行的數(shù)量比較之。另外,如果輸入的數(shù)據(jù)行和列的和都不一樣,那么不需要判斷,必然有天使改變狀態(tài),直接輸出Terrible,否則輸出Not Sure。
圖論的算法都是非常靈活的,很多問題看似和圖沒有關(guān)系,都能夠最終轉(zhuǎn)化到圖論上。。關(guān)鍵還是在于建圖,只能不斷總結(jié),多做題。
AC:
#include<stdio.h> #include<string.h> #include <iostream> using namespace std; #define INF 1<<29; int s,t; //s:源點(diǎn) t:匯點(diǎn) int m; //頂點(diǎn)數(shù) int cf[605][605]; //殘留容量 int flow; //當(dāng)前最大流 int cf_path; //本次可增廣的流量(本次增廣路徑的殘留容量) bool flag; //本次增廣路徑是否找到 int vh[1000]; //各高度的頂點(diǎn)個(gè)數(shù) int h[1000]; //各頂點(diǎn)的高度,又稱為“距離標(biāo)號(hào)”——到匯點(diǎn)距離的下界(邊權(quán)值都為1) void sap() {flow =cf_path=s=t=0;flag=false;memset(cf,0,sizeof(cf));memset(vh,0,sizeof(vh));memset(h,0,sizeof(h)); } void find_path_sap(int cur) {if(cur==t){flow++;flag=true;return;}int i;int minH=m*2;int tmp_cf_path=cf_path;for(i=0;i<=m;i++){if(cf[cur][i]){if(h[i]+1==h[cur]){find_path_sap(i);if(h[1]>=m) return;if(flag) break;//此句不加會(huì)錯(cuò)、、、}if(h[i]<minH) minH=h[i];}}if(flag){cf[cur][i]--;cf[i][cur]++;}else{vh[h[cur]]--;if(vh[h[cur]]==0) h[0]=m;h[cur]=minH+1;vh[h[cur]]++;} } int solve() {vh[0]=m;flow=0;while(h[0]<m)//h[1]保持<m,一旦增長到m,就不再存在任何增廣路徑{flag=false;cf_path=INF;find_path_sap(s);}return flow; } void addEdge(int x,int y,int c) {cf[x][y]+=c; } int main() {int mm,a;scanf("%d",&a);while(a--){int cn,n;scanf("%d%d",&cn,&n);sap();mm=cn+n+3;s=0;t=mm;m=mm;int i,cf=0,kf=0;for(i=1;i<=cn;i++){int c;scanf("%d",&c);cf+=c;addEdge(0,i,c);for(int j=cn+1;j<=cn+n;j++)addEdge(i,j,1);}for(i=cn+1;i<=cn+n;i++){int x;scanf("%d",&x);kf+=x;addEdge(i,cn+n+3,x);}if(cf!=kf)printf("Terrible\n");else{int hs;hs=solve();if(cf==hs)printf("Not Sure\n");else printf("Terrible\n");}}return 0; }
總結(jié)
- 上一篇: extundelete反删除总结
- 下一篇: hdu 4289(最小割最大流定理)