国防科技大学2019校赛G Altitude(平面图转对偶图找最小割)
https://ac.nowcoder.com/acm/contest/878/G
题目大意
给出一副网格,其中每条边上往来都有一些人流,网格的每个交叉点都有一个高度,网格的每条边连接着两个交叉点,人流的代价为向高处走的高度差乘上人流的人数。向低处或者相同高度处走不需要付出代价。网格的左上角的高度为0,网格右下角的高度为1。问整张图的最小代价为多少
解题思路
由于下降和相同高度之间往来不需要代价,因此,网格交点的高度只可能是0或者1,更进一步说,只需要对原本的网格图划分成两部分即可,一部分包含左上角高度都为0,另一部分包含右下角高度都为1,这样就只有两部分交界处的边有费用。那么求整张图的最小费用就变成了求图的一个划分,使得划分的边的权值和最小,也就变成了求一个最小割。由于本题数据范围的限制以及原图为一平面图,因此可以将原图转化为对偶图,通过求最短的的方式求最小割
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=1ll<<60;
const int maxn=3e5+10;
struct Edge{
int v,nxt;
ll w;
} edge[maxn<<2];
int head[maxn],cnt;
ll dis[maxn];
int n;
struct Node{
int id;
ll w;
bool operator <(const Node &b) const {return w>b.w;}
};
void Init()
{
memset(head,-1,sizeof(head));
cnt=0;
}
void addedge(int u,int v,ll w)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
void Dij(int s)
{
for(int i=0;i<=n*n+1;++i) dis[i]=INF;
dis[s]=0;
priority_queue<Node> q;
q.push(Node{s,0});
while(!q.empty())
{
Node u=q.top();q.pop();
int Id=u.id;
if(dis[Id]!=u.w) continue;
for(int i=head[Id];~i;i=edge[i].nxt)
{
int v=edge[i].v;
if(dis[v]>dis[Id]+edge[i].w)
{
dis[v]=dis[Id]+edge[i].w;
q.push(Node{v,dis[v]});
}
}
}
}
int main()
{
while(~scanf("%d",&n))
{
Init();
int s=0,t=n*n+1;
ll val;
// w-->e
for(int i=1;i<=n;++i) scanf("%lld",&val),addedge(i,t,val);
for(int i=1;i<=n*(n-1);++i)
{
scanf("%lld",&val);
//addedge(i,i+n,val);
addedge(i+n,i,val);
}
for(int i=1;i<=n;++i) scanf("%lld",&val),addedge(s,n*(n-1)+i,val);
for(int i=1;i<=n;++i)
{
for(int j=0;j<=n;++j)
{
scanf("%lld",&val);
if(j==0){addedge(s,(i-1)*n+1,val);}//×ó²Ã
else if(j==n){addedge(i*n,t,val);}// you
else {addedge(j+n*(i-1),j+n*(i-1)+1,val);}// zhong
}
}
//e-->w
for(int i=1;i<=n;++i) scanf("%lld",&val),addedge(t,i,val);
for(int i=1;i<=n*(n-1);++i)
{
scanf("%lld",&val);
addedge(i,i+n,val);
//addedge(i+n,i,val);
}
for(int i=1;i<=n;++i) scanf("%lld",&val),addedge(n*(n-1)+i,s,val);
//s-->n
for(int i=1;i<=n;++i)
{
for(int j=0;j<=n;++j)
{
scanf("%lld",&val);
if(j==0){addedge((i-1)*n+1,s,val);}//×ó²Ã
else if(j==n){addedge(t,i*n,val);}// you
else {addedge(j+n*(i-1)+1,j+n*(i-1),val);}// zhong
}
}
// n-->s
//for(int i=1;i<=n*(n+1);++i) scanf("%d",&val);
Dij(s);
printf("%lld\n",dis[t]);
}
return 0;
}