战争
战争
时间限制: 5 Sec 内存限制: 256 MB提交: 105 解决: 18
[提交][状态][讨论版]
题目描述
A国正遭受敌人的袭击,敌国的军队已经到达Y城市。Y城市由N*M的方格组成。城市中所有的道路都是双向的,水平、垂直或者斜线方向的。在地图左上角是(0,0)点,右下角是(N,M)点。敌国军队现在到达(0,0)点,为了攻占A国,他们必须经过Y城市到达(N,M)点,下图是一个Y城市的交通图。
每一个黑色顶点代表城市中的主要建筑群,他们之间有道路相连。在这些道路上面的数值表示炸毁该条道路所需要的TNT。。。A国的防御部队已经无法抵御敌军的正面进攻,他们能做的就是通过炸毁道路阻止敌军通过Y城市而到达A国首都。现在作为A国国防部长,你需要决定炸毁哪些街道,使得敌军无法从(0,0)点到达(N,M)点,并且使用尽可能少的TNT。
输入
有多组测试数据。
第一行两个正数N,M,表示地图的高和宽
接下来N+1行,每行M个整数,依次对应该图中水平的道路
接下来N行,每行M+1个整数,依次对应图中垂直的道路
接下来2N行,每行2M个整数,依次对应图中斜线的道路。
数据有多组,以EOF结束. (最后貌似有多余回车符,Pascal的童鞋可能会读到N=0,C++的直接无视)
数据范围:
30%的数据1 <= N, M <= 50
100%的数据:
1 <= N, M <= 500
1 <= amount <= 1,000,000
输出
输出一个整数,表示断开(0,0)点和(N,M)点所需的最少TNT数量。
样例输入
2 3
1 9 4
1 8 7
6 2 3
7 5 4 8
6 2 8 7
10 4 1 7 5 3
5 4 10 2 1 9
6 3 2 9 5 3
8 9 6 3 10 10
样例输出
18
这道题是可以用最小割做的,但是复杂度实在是太高了,所以我们看题面有什么限制,发现是平面图
对于一个图G=< V,E >,如果能把G画在一个平面上,且画出的图的任意两条边除了V中的节点没有其他交点,则图G为平面图
这个性质是有启发的,怎么求最小割的呢,就是使源点到汇点不连通,这样在平面图中,不就是使上面与下面,通过空白
然后相联通即可,这样就是空白块之间相互联通,求一次大空白块之间的最短路就是了。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 #include<queue> 6 #include<iostream> 7 using namespace std; 8 9 typedef pair<int,int>fzy; 10 const int NN=1001007; 11 12 int n,m,S,T; 13 int cnt=0,head[NN],dis[NN],next[NN*6],rea[NN*6],val[NN*6]; 14 struct cmp 15 { 16 bool operator() (fzy a,fzy b) 17 { 18 return a.first>b.first; 19 } 20 }; 21 void Dijkstra() 22 { 23 bool boo[NN]; 24 priority_queue<fzy,vector<fzy>,cmp > q; 25 while (!q.empty()) 26 q.pop(); 27 memset(boo,0,sizeof(boo)); 28 memset(dis,100,sizeof(dis)); 29 dis[S]=0; 30 q.push(make_pair(0,S)); 31 while (!q.empty()) 32 { 33 fzy now=q.top(); 34 q.pop(); 35 if (boo[now.second]) continue; 36 boo[now.second]=1; 37 int u=now.second; 38 for (int i=head[u];i!=-1;i=next[i]) 39 { 40 int v=rea[i],fee=val[i]; 41 if (dis[u]+fee<dis[v]) 42 { 43 dis[v]=dis[u]+fee; 44 q.push(make_pair(dis[v],v)); 45 } 46 } 47 } 48 printf("%d\n",dis[T]); 49 } 50 void add(int u,int v,int fee) 51 { 52 cnt++; 53 next[cnt]=head[u]; 54 head[u]=cnt; 55 rea[cnt]=v; 56 val[cnt]=fee; 57 } 58 int main() 59 { 60 while (~scanf("%d%d",&n,&m)) 61 { 62 cnt=0; 63 memset(head,-1,sizeof(head)); 64 S=n*m*4+1,T=n*m*4+2; 65 int x; 66 for (int i=1;i<=n+1;i++) 67 for (int j=1;j<=m;j++) 68 { 69 scanf("%d",&x); 70 if (i==1) add(S,((i-1)*m+j-1)*4+1,x),add(((i-1)*m+j-1)*4+1,S,x); 71 else if (i==n+1) add(T,((i-2)*m+j-1)*4+3,x),add(((i-2)*m+j-1)*4+3,T,x); 72 else add(((i-2)*m+j-1)*4+3,((i-1)*m+j-1)*4+1,x),add(((i-1)*m+j-1)*4+1,((i-2)*m+j-1)*4+3,x); 73 } 74 for (int i=1;i<=n;i++) 75 for (int j=1;j<=m+1;j++) 76 { 77 scanf("%d",&x); 78 if (j==1) add(T,((i-1)*m+j-1)*4+2,x),add(((i-1)*m+j-1)*4+2,T,x); 79 else if (j==m+1) add(S,((i-1)*m+j-2)*4+4,x),add(((i-1)*m+j-2)*4+4,S,x); 80 else add(((i-1)*m+j-1)*4+2,((i-1)*m+j-2)*4+4,x),add(((i-1)*m+j-2)*4+4,((i-1)*m+j-1)*4+2,x); 81 } 82 for (int i=1;i<=2*n;i++) 83 for (int j=1;j<=2*m;j++) 84 { 85 scanf("%d",&x); 86 if (i%2==1&&j%2==1) add(((i-1)/2*m+(j-1)/2)*4+2,((i-1)/2*m+(j-1)/2)*4+1,x),add(((i-1)/2*m+(j-1)/2)*4+1,((i-1)/2*m+(j-1)/2)*4+2,x); 87 if (i%2==1&&j%2==0) add(((i-1)/2*m+(j-1)/2)*4+1,((i-1)/2*m+(j-1)/2)*4+4,x),add(((i-1)/2*m+(j-1)/2)*4+4,((i-1)/2*m+(j-1)/2)*4+1,x); 88 if (i%2==0&&j%2==1) add(((i-1)/2*m+(j-1)/2)*4+2,((i-1)/2*m+(j-1)/2)*4+3,x),add(((i-1)/2*m+(j-1)/2)*4+3,((i-1)/2*m+(j-1)/2)*4+2,x); 89 if (i%2==0&&j%2==0) add(((i-1)/2*m+(j-1)/2)*4+3,((i-1)/2*m+(j-1)/2)*4+4,x),add(((i-1)/2*m+(j-1)/2)*4+4,((i-1)/2*m+(j-1)/2)*4+3,x); 90 } 91 Dijkstra(); 92 } 93 }
建图比较复杂,让人厌烦,但找到规律后还是很快的。