HDU3870 Catch the Theves(平面图最小割转最短路)
2016-05-03 17:12
417 查看
题目大概说给一个n×n的方格,边有权值,问从求(1,1)到(n,n)的最小割。
点达到了160000个,直接最大流不好。这题的图是平面图,求最小割可以转化成求其对偶图的最短路,来更高效地求解:
首先源点汇点间新加一条边,然后构造其对偶图:
面作为对偶图的点;而源点到汇点之间新加的边划分出来的两个面分别作为对偶图的源点和汇点
如果两个面之间有边则两个面在对偶图对应的点连边,权值为原来的边权;去掉对偶图源点和汇点之间边
这样可以发现,对偶图的源点到汇点的一条路径就对应这原图的源点到汇点的一个割边集,而最短路就对应最小割了。所以求一下最小割就OK了,我用SPFA好像超时了,改用堆优化的Dijkstra,10W个点OK。
点达到了160000个,直接最大流不好。这题的图是平面图,求最小割可以转化成求其对偶图的最短路,来更高效地求解:
首先源点汇点间新加一条边,然后构造其对偶图:
面作为对偶图的点;而源点到汇点之间新加的边划分出来的两个面分别作为对偶图的源点和汇点
如果两个面之间有边则两个面在对偶图对应的点连边,权值为原来的边权;去掉对偶图源点和汇点之间边
这样可以发现,对偶图的源点到汇点的一条路径就对应这原图的源点到汇点的一个割边集,而最短路就对应最小割了。所以求一下最小割就OK了,我用SPFA好像超时了,改用堆优化的Dijkstra,10W个点OK。
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define INF (1<<30) #define MAXN 1111*1111 struct Edge{ int v,w,next; }edge[MAXN<<1]; int vs,vt,NV,NE,head[MAXN]; void addEdge(int u,int v,int w){ edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u]; head[u]=NE++; } struct Node{ int u,d; Node(int _u=0,int _d=0):u(_u),d(_d){} bool operator<(const Node &nd)const{ return nd.d<d; } }; int d[MAXN]; bool vis[MAXN]; int dijkstra(){ for(int i=0; i<NV; ++i){ d[i]=INF; vis[i]=0; } d[vs]=0; priority_queue<Node> que; que.push(Node(vs,0)); while(!que.empty()){ Node nd=que.top(); que.pop(); if(nd.u==vt) return nd.d; if(vis[nd.u]) continue; vis[nd.u]=1; for(int i=head[nd.u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(vis[v]) continue; if(d[v]>d[nd.u]+edge[i].w){ d[v]=d[nd.u]+edge[i].w; que.push(Node(v,d[v])); } } } return INF; } int a[444][444]; int main(){ int t,n; scanf("%d",&t); while(t--){ scanf("%d",&n); if(n==1){ puts("0"); continue; } vs=(n-1)*(n-1); vt=vs+1; NV=vt+1; NE=0; memset(head,-1,sizeof(head)); for(int i=0; i<n; ++i){ for(int j=0; j<n; ++j){ scanf("%d",&a[i][j]); } } for(int i=0; i<n-1; ++i){ for(int j=0; j<n; ++j){ if(j==0){ addEdge(vs,i*(n-1)+j,a[i][j]); }else if(j==n-1){ addEdge(i*(n-1)+j-1,vt,a[i][j]); }else{ addEdge(i*(n-1)+j,i*(n-1)+j-1,a[i][j]); addEdge(i*(n-1)+j-1,i*(n-1)+j,a[i][j]); } } } for(int j=0; j<n-1; ++j){ for(int i=0; i<n; ++i){ if(i==0){ addEdge(i*(n-1)+j,vt,a[i][j]); }else if(i==n-1){ addEdge(vs,(i-1)*(n-1)+j,a[i][j]); }else{ addEdge(i*(n-1)+j,(i-1)*(n-1)+j,a[i][j]); addEdge((i-1)*(n-1)+j,i*(n-1)+j,a[i][j]); } } } printf("%d\n",dijkstra()); } return 0; }
相关文章推荐
- 【框架】recyclerView(可替代ListView)
- Java 8怎么了之二:函数和原语
- 十道海量数据处理面试题与十个方法大总结(转)
- 语言检测工具language-detection 的简单使用
- SHELL syntax error:unexpected end of file 提示错误
- GitHub 基本命令(一)
- 【Unity3D游戏开发】基于NGUI的表情图文混排解决方案 (二二)
- ScrollView和ViewPager滑动冲突的解决和整理
- Android MediaPlayer
- HDU 2859 Phalanx
- 初步认识shell
- Bloom Filter(布隆过滤器)
- X86 通用寄存器使用惯例
- 2.JS中的数据类型与变量
- Java 8怎么了之二:函数和原语
- windowManager.addView()抛出WindowManager$InvalidDisplayException异常
- 第十一周补充项目 3.1点直线类
- 二、进程间通信
- Android 短信拦截及用途分析
- 1-6-06:校门外的树