BZOJ1001 狼抓兔子 终于过了!
时间来不及了,先贴代码吧!有时间再写。
好苦逼啊,WA了若干次,还有一次RE,一次TLE。
虽然主要运用的算法和资料都由师兄提供了。还是太弱了,太天真了。
首先,数据范围就WA了,RE了,TLE了。
然后构图上有bug。最后还是仿着师兄的把构图重新写了。加油吧!
这道题的主要思路首先应该是网络流中的最小割,但由于数据范围太大,直接用最小割的算法会TLE,而且没有正确地利用题目特征,这道题的图是个S-T图,我们可以建出原图的对偶图,然后跑一次dijkstra()。详情请参考《浅析最大最小定理在信息学竞赛中的应用》。
一个网格图中求最小割,很特殊的是这个图是一个平面图,最小割=最大流=对偶图中最短路(平面图)。
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 #include<cstring> 5 #define maxn 2100009 6 #define rep(i,j,k) for(int i = j; i <= k; i++) 7 using namespace std; 8 9 int read() 10 { 11 int s = 0, t = 1; char c = getchar(); 12 while( !isdigit(c) ) { 13 if( c == '-' ) t = -1; c = getchar(); 14 } 15 while( isdigit(c) ){ 16 s = s * 10 + c - '0'; c = getchar(); 17 } 18 return s * t; 19 } 20 21 int d[maxn], n, m, sx, tx; 22 bool done[maxn] = {0}; 23 24 struct node{ 25 int d, u; 26 bool operator < (const node& rhs) const{ 27 return d > rhs.d; 28 } 29 }; 30 31 struct edge{ 32 int to, key; 33 edge* next; 34 }; 35 36 edge *pt, edges[maxn*3], *head[maxn]; 37 38 void add_edge(int x,int y,int val){ 39 pt->to = y;pt->key = val; 40 pt->next = head[x]; 41 head[x] = pt++; 42 pt->to = x, pt->key= val; 43 pt->next = head[y]; 44 head[y] = pt++; 45 } 46 priority_queue<node> Q; 47 48 void dijkstra() 49 { 50 memset(d,127,sizeof(d)); 51 d[sx] = 0; 52 Q.push((node){0,sx}); 53 while( !Q.empty() ){ 54 node x = Q.top(); Q.pop(); 55 int u = x.u; 56 if( done[u] ) continue; 57 done[u] = 1; 58 for( edge*i = head[u]; i ; i = i->next ){ 59 int y = i->to, key = i->key; 60 if( d[y] > d[u]+key ) { 61 d[y] = d[u]+key; 62 Q.push((node){d[y],y}); 63 } 64 } 65 } 66 } 67 68 int main() 69 { 70 //freopen("out.txt","w",stdout); 71 pt = edges; 72 n = read(), m = read(); 73 sx = 0, tx = (n-1)*(m-1) * 2+ 1; 74 rep(i,0,n-1) { 75 int xx = (2*m-2)*i; 76 int xy = (2*m-2)*(i-1); 77 rep(j,1,m-1){ 78 int x = read(); 79 if( !i ) { 80 add_edge(xx+2*j,tx,x); 81 //cout<<tx<<" "<<xx+2*j+1<<" "<<x<<endl; 82 } 83 else if( i == n-1 ) { 84 add_edge(sx,xy+2*j-1,x); 85 //cout<<xy+2*j<<" "<<sx<<" "<<x<<endl; 86 } 87 else{ 88 add_edge(xx+2*j,xy+2*j-1,x); 89 //cout<<xy+2*j<<" "<<xx+2*j+1<<" "<<x<<endl; 90 } 91 } 92 } 93 rep(i,0,n-2){ 94 int xx = 2*(m-1)*(i); 95 rep(j,1,m){ 96 int x = read(); 97 if( j == 1 ){ 98 add_edge(sx,xx+2*j-1,x); 99 //cout<<sx<<" "<<xx<<" "<<x<<endl; 100 } 101 else if( j == m ){ 102 add_edge(tx,xx+2*j-2,x); 103 //cout<<tx<<" "<<xx+2*j-1<<" "<<x<<endl; 104 } 105 else { 106 add_edge(xx+2*j-2,xx+2*j-1,x); 107 //cout<<xx+2*j<<" "<<xx+2*j-1<<" "<<x<<endl; 108 } 109 } 110 } 111 rep(i,0,n-2){ 112 int xx = 2*(m-1)*(i); 113 rep(j,1,m-1){ 114 int x = read(); 115 add_edge(xx+2*j,xx+2*j-1,x); 116 //cout<<xx+2*j<<" "<<xx+2*j+1<<" "<<endl; 117 } 118 } 119 dijkstra(); 120 cout<<d[tx]<<endl; 121 return 0; 122 }
不过,也想请大神把我指出下面这份代码错哪了?
1 #include<cstdio> 2 #include<iostream> 3 #include<queue> 4 #include<cstring> 5 #define maxn 2100009 6 #define sx 2100000 7 #define tx 2100001 8 #define rep(i,j,k) for(int i = j; i <= k; i++) 9 using namespace std; 10 11 int read() 12 { 13 int s = 0, t = 1; char c = getchar(); 14 while( !isdigit(c) ) { 15 if( c == '-' ) t = -1; c = getchar(); 16 } 17 while( isdigit(c) ){ 18 s = s * 10 + c - '0'; c = getchar(); 19 } 20 return s * t; 21 } 22 23 int d[maxn], n, m; 24 bool done[maxn] = {0}; 25 26 struct node{ 27 int d, u; 28 bool operator < (const node& rhs) const{ 29 return d > rhs.d; 30 } 31 }; 32 33 struct edge{ 34 int to, key; 35 edge* next; 36 }; 37 38 edge *pt, edges[maxn*3], *head[maxn]; 39 40 void add_edge(int x,int y,int val){ 41 pt->to = y;pt->key = val; 42 pt->next = head[x]; 43 head[x] = pt++; 44 pt->to = x, pt->key= val; 45 pt->next = head[y]; 46 head[y] = pt++; 47 } 48 priority_queue<node> Q; 49 50 void dijkstra() 51 { 52 memset(d,127,sizeof(d)); 53 d[sx] = 0; 54 Q.push((node){0,sx}); 55 while( !Q.empty() ){ 56 node x = Q.top(); Q.pop(); 57 int u = x.u; 58 if( done[u] ) continue; 59 done[u] = 1; 60 for( edge*i = head[u]; i ; i = i->next ){ 61 int y = i->to, key = i->key; 62 if( d[y] > d[u]+key ) { 63 d[y] = d[u]+key; 64 Q.push((node){d[y],y}); 65 } 66 } 67 } 68 } 69 70 int main() 71 { 72 //freopen("out.txt","w",stdout); 73 pt = edges; 74 n = read(), m = read(); 75 rep(i,0,n-1) { 76 int xx = (2*m-2)*i; 77 int xy = (2*m-2)*(i-1); 78 rep(j,0,m-2){ 79 int x = read(); 80 if( !i ) { 81 add_edge(xx+2*j+1,tx,x); 82 //cout<<tx<<" "<<xx+2*j+1<<" "<<x<<endl; 83 } 84 else if( i == n-1 ) { 85 add_edge(sx,xy+2*j,x); 86 //cout<<xy+2*j<<" "<<sx<<" "<<x<<endl; 87 } 88 else{ 89 add_edge(xx+2*j+1,xy+2*j,x); 90 //cout<<xy+2*j<<" "<<xx+2*j+1<<" "<<x<<endl; 91 } 92 } 93 } 94 rep(i,0,n-2){ 95 int xx = 2*(m-1)*(i); 96 rep(j,0,m-1){ 97 int x = read(); 98 if( !j ){ 99 add_edge(sx,xx,x); 100 //cout<<sx<<" "<<xx<<" "<<x<<endl; 101 } 102 else if( j == m-1 ){ 103 add_edge(tx,xx+2*j-1,x); 104 //cout<<tx<<" "<<xx+2*j-1<<" "<<x<<endl; 105 } 106 else { 107 add_edge(xx+2*j,xx+2*j-1,x); 108 //cout<<xx+2*j<<" "<<xx+2*j-1<<" "<<x<<endl; 109 } 110 } 111 } 112 rep(i,0,n-2){ 113 int xx = 2*(m-1)*(i); 114 rep(j,0,m-2){ 115 int x = read(); 116 add_edge(xx+2*j,xx+2*j+1,x); 117 //cout<<xx+2*j<<" "<<xx+2*j+1<<" "<<endl; 118 } 119 } 120 dijkstra(); 121 cout<<d[tx]<<endl; 122 return 0; 123 }
1001: [BeiJing2006]狼抓兔子
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 14595 Solved: 3490
[Submit][Status][Discuss]
Description
现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 1:(x,y)<==>(x+1,y) 2:(x,y)<==>(x,y+1) 3:(x,y)<==>(x+1,y+1) 道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦.
Input
第一行为N,M.表示网格的大小,N,M均小于等于1000.接下来分三部分第一部分共N行,每行M-1个数,表示横向道路的权值. 第二部分共N-1行,每行M个数,表示纵向道路的权值. 第三部分共N-1行,每行M-1个数,表示斜向道路的权值. 输入文件保证不超过10M
Output
输出一个整数,表示参与伏击的狼的最小数量.
Sample Input
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6