描述
http://www.lydsy.com/JudgeOnline/problem.php?id=1001
分析
平面图求最小割,转化成对偶图求最短路,经典.
注意:
1.优先队列是个大根堆.
2.Dijkstra可以带一个vis数组,也可以不带,因为一个点出来以后,它更新的的点和原本就在队列里的点都比它大,所以它不可能被更新得更小,之后这个点再出队时情况不比第一次更优,所以出队也不会有操作.
3.双向边,数组要开够(貌似不是第一次犯这个错误).
4.网上有人说m==1||n==1的情况可以不特判,在get函数中已经可以处理妥当,大丈夫.
#include <cstdio> #include <queue> #include <algorithm> using namespace std; const int maxn=1000+10,oo=1<<27; int n,m,cnt; int d[maxn*maxn*2],head[maxn*maxn*4]; bool vis[maxn*maxn*2]; struct edge{ int to,w,next; edge(){} edge(int a,int b,int c):to(a),w(b),next(c){} bool operator<(const edge &a) const { return a.w<w; } }g[maxn*maxn*6]; void insert(int from,int to,int w){ g[++cnt]=edge(to,w,head[from]); head[from]=cnt; g[++cnt]=edge(from,w,head[to]); head[to]=cnt; } int get(int x,int y,int z){ if(x<1||y>=m) return ((n-1)*(m-1)<<1)+1; if(x>=n||y<1) return 0; return (((x-1)*(m-1)+y-1)<<1)+z+1; } int Dijkstra(int s,int t){ for(int i=0;i<=((n-1)*(m-1)<<1)+1;i++) d[i]=oo; d[s]=0; priority_queue <edge> q; q.push(edge(s,0,0)); while(!q.empty()){ edge e=q.top(); q.pop(); int x=e.to; if(vis[x]) continue; vis[x]=true; for(int i=head[x];i;i=g[i].next){ int y=g[i].to; if(d[y]>d[x]+g[i].w){ d[y]=d[x]+g[i].w; q.push(edge(y,d[y],0)); } } } return d[t]; } void init(){ for(int i=1;i<=n;i++){ for(int j=1;j<m;j++){ int a; scanf("%d",&a); insert(get(i,j,1),get(i-1,j,0),a); } } for(int i=1;i<n;i++){ for(int j=1;j<=m;j++){ int a; scanf("%d",&a); insert(get(i,j-1,1),get(i,j,0),a); } } for(int i=1;i<n;i++){ for(int j=1;j<m;j++){ int a; scanf("%d",&a); insert(get(i,j,0),get(i,j,1),a); } } } int main(){ scanf("%d%d",&n,&m); init(); printf("%d\n",Dijkstra(0,((n-1)*(m-1)<<1)+1)); return 0; }
时间: 2024-12-18 21:58:33