题意:给定一个N*N的网格,每个格点均与周围的八个点连边,每条边有一个边权,求安排每个点的点权h,使$\sum\limits_{e \in G} {e.w \times \min \{ ({h_{e.u}} - {h_{e.v}}),0\} }$最小
题解:所有高度一定不是0就是1,而且一定有一条线使得这条线一边是0,另一边是1。显然最小割。然后这是个平面图,Dijkstra随便跑。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <queue> #include <functional> #include <cstdio> #include <cstring> #include <cstdlib> #include <climits> #include <iostream> #include <algorithm> using namespace std; const int MAXN=500+2; const int MAXM=6000000+2; struct HASH{ int u,w; HASH *next; HASH(){} HASH(int _u,int _w,HASH *_next):u(_u),w(_w),next(_next){} }*table[MAXM],mem[MAXM]; struct EDGE{ int u,w; EDGE(){} EDGE(int _u,int _w):u(_u),w(_w){} bool friend operator<(EDGE a,EDGE b){ a.w>a.w;} }; int N,cnt,g[MAXN][MAXN],d[MAXM]; priority_queue<EDGE> q; void Insert(int u,int v,int w){ table[u]=&(mem[cnt++]=HASH(v,w,table[u]));} int Dijkstra(int s,int t){ memset(d,0X7F,sizeof(d)); d[s]=0,q.push(EDGE(s,0)); int x; while(!q.empty()){ x=q.top().u,q.pop(); for(HASH *p=table[x];p;p=p->next) if(d[p->u]>d[x]+p->w){ d[p->u]=d[x]+p->w; q.push(EDGE(p->u,d[p->u])); } } return d[t]; } int main(){ cin >> N; cnt=1; for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) g[i][j]=++cnt; for(int i=1;i<=N;i++) g[i][0]=g[N+1][i]=1; cnt=0; for(int i=1,w;i<=N+1;i++) for(int j=1;j<=N;j++){ cin >> w; Insert(g[i-1][j],g[i][j],w); } for(int i=1,w;i<=N;i++) for(int j=1;j<=N+1;j++){ cin >> w; Insert(g[i][j],g[i][j-1],w); } for(int i=1,w;i<=N+1;i++) for(int j=1;j<=N;j++){ cin >> w; Insert(g[i][j],g[i-1][j],w); } for(int i=1,w;i<=N;i++) for(int j=1;j<=N+1;j++){ cin >> w; Insert(g[i][j-1],g[i][j],w); } cout << Dijkstra(0,1) << endl; return 0; }