1324: Exca王者之剑
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 512 Solved: 261
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
1 2
2 1
Sample Output
二分图最小点权覆盖
从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。
建模:
原二分图中的边(u,v)替换为容量为INF的有向边(u,v),设立源点s和汇点t,将s和x集合中的点相连,容量为该点的权值;将y中的点同t相连,容量为该点的权值。在新图上求最大流,最大流量即为最小点权覆盖的权值和。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,m,len,S,T,ans;
int to[1000000],next[1000000],zhi[1000000],h[1000000];
int dis[21000],q[210000];
int a[110][110];
int g[3][5]={0,0,0,0,0,
0,1,-1,0,0,
0,0,0,1,-1};
inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}
void insert(int x,int y,int z)
{
++len; to[len]=y; next[len]=h[x]; zhi[len]=z; h[x]=len;
}
bool bfs()
{
memset(dis,-1,sizeof(dis)); int tail=1,head=0; q[tail]=S; dis[S]=0;
while (head<tail)
{
++head;
int u=h[q[head]];
while (u!=0)
{
if (dis[to[u]]==-1 && zhi[u])
{
dis[to[u]]=dis[q[head]]+1;
++tail; q[tail]=to[u];
}
u=next[u];
}
}
if (dis[T]!=-1) return true;else return false;
}
int dicnic(int now,int sum)
{
if (now==T) return sum;
int sug=0;
int u=h[now];
while (u!=0)
{
if (zhi[u]>0 && dis[to[u]]==dis[now]+1)
{
int s=dicnic(to[u],min(sum-sug,zhi[u]));
if (s)
{
sug+=s; zhi[u]-=s; zhi[u^1]+=s;
if (sug==sum) return sum;
}
}
u=next[u];
}
if (sug==0) dis[now]=-1; return sug;
}
int main()
{
len=1;
n=read(); m=read();
S=0; T=n*m*2+1; int so=0;
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
{
a[i][j]=read(); so+=a[i][j];
int u1=(i-1)*m+j; int u2=(i-1)*m+j+n*m;
insert(S,u1,a[i][j]); insert(u1,S,0);
insert(u2,T,a[i][j]); insert(T,u2,0);
}
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
{
int ug=(i-1)*m+j;
for (int k=1;k<=4;++k)
{
int u1=i+g[1][k]; int u2=j+g[2][k];
if (u1>0 && u1<=n && u2>0 && u2<=m)
{
int uh=(u1-1)*m+u2+n*m;
insert(ug,uh,0x7fffffff); insert(uh,ug,0);
}
}
}
ans=0;
while (bfs())
{
ans+=dicnic(S,0x7fffffff);
}
printf("%d",so-ans/2);
}