A-HOJ1646
- 题意:N个点M条的无向图,求图的连通度(即删掉最少个点使图不连通)
- 思路:枚举源点汇点,跑一边最小割。而题目要求删点而不是删边。故拆点,将I拆成I和I+n,I向I+n连容量为1的边。原图中的边连两条有向边。I向J+n,J向I+n,容量INF。每次割的最小值便是连通度。若要割掉N个点才不连通,则说明原图的连通度为N。
using namespace std;
struct nod{int end,next,c;
}g[mm*5],G[mm*5];
char A[14];
int tot,i,tem,n,j,c,z,ans,S,F,D,T,a,b,w,m;
int dis[nn],cur[nn],fa[nn],q[nn*6];
void add(int a,int b,int c)
{g[tot]=(nod){b,fa[a],c};fa[a]=tot++;
g[tot]=(nod){a,fa[b],0};fa[b]=tot++;
}
bool bfs()
{int t,w,u,x;
memset(dis,-1,sizeof(dis));
dis[q[1]=S]=0;
for (t=0,w=1;t<w;){
x=q[++t];if (x==T)return 1;
for (int i=fa[x];i!=-1;i=g[i].next)
{u=g[i].end;
if (dis[u]==-1&&g[i].c)
{dis[u]=dis[x]+1;q[++w]=u;}
}}
return 0;
}
int dfs(int w,int tem)
{int c,u,ok=0;
if (w==T)return tem;
for (int i=fa[w];i!=-1;i=g[i].next){
u=g[i].end;
if (dis[u]==dis[w]+1&&g[i].c){
c=dfs(u,min(tem-ok,g[i].c));
g[i].c-=c;g[i^1].c+=c;
ok+=c;
if (ok==tem)return tem;
}
}
if (!ok)dis[w]=-1;
return ok;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF){
if (n==0||n==1){
for (int i=1;i<=m;i++){
scanf("%s",A);
}
printf("%d\n",n);continue;
}
memset(fa,-1,sizeof(fa));tot=0;
for (int i=0;i<n;i++)add(i,i+n,1);
for (int i=1;i<=m;i++){
scanf(" (%d,%d)",&a,&b);
add(a+n,b,inf);
add(b+n,a,inf);
}
for (int i=0;i<tot;i++)G[i]=g[i];
tem=inf;
for (int i=0;i<n;i++)
for (int j=i+1;j<n;j++){
S=i+n;T=j;
ans=0;
while (bfs()){
ans+=dfs(S,inf);
}
for (int k=0;k<tot;k++)g[k].c=G[k].c;
tem=min(tem,ans);
}
printf("%d\n",(tem>=n)?n:tem);
}
return 0;
}
B-HDU1596
- 题意:给你一个m*n的格子的棋盘,每个格子里面有一个非负数。从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
- 思路:此题思路和下面H题思路相似。考虑网络流最小割。首先易想到根据棋盘奇偶性分离两个集合X,Y;建图:首先从S向X中的数连容量为其权值的边,其次从Y中的数向T连容量为其权值的边。然后若X和Y中的某个数相邻,则连一条为INF的边。为什么这么连呢?
- 若跑完最小割,X中的I任于S相连,则表明选I这个数,那么若和I相邻的数
J也选,而他们之间又有一条INF的边,所以程序不会去割他,但任然有增广路,则矛盾。 - 若X中的I不与S相连,则表示不取这个数。则跑完整个图便是,不取一些数,和最小,且满足选的数不相邻。所以TOT-ans即为解。
using namespace std;
typedef long long ll;
const ll inf=100000000000ll;
struct nod{ll end,next,c;
}g[mm*2];
const ll han[4]={1,0,0,-1};
const ll lie[4]={0,1,-1,0};
ll tot,i,n,z,ci,ans,sum,S,T,a,b,w,m;
ll dis[nn],cur[nn],fa[nn],q[nn*5];
void add(ll a,ll b,ll c)
{g[tot]=(nod){b,fa[a],c};fa[a]=tot++;
g[tot]=(nod){a,fa[b],0};fa[b]=tot++;
}
bool bfs()
{ll t,w,i,u,x;
memset(dis,-1,sizeof(dis));
dis[q[1]=S]=0;
for (t=0,w=1;t<w;){
x=q[++t];
for (i=fa[x];i!=-1;i=g[i].next)
{u=g[i].end;
if (dis[u]==-1&&g[i].c)
{dis[u]=dis[x]+1;q[++w]=u;
if (u==T)return 1;
}
}}
return 0;
}
ll dfs(ll w,ll tem)
{ll c,i,u,ok=0;
if (w==T)return tem;
for (ll &i=cur[w];i!=-1;i=g[i].next){
u=g[i].end;
if (dis[u]==dis[w]+1&&g[i].c){
c=dfs(u,min(tem-ok,g[i].c));
g[i].c-=c;g[i^1].c+=c;
ok+=c;
if (ok==tem)return tem;
}
}
if (!ok)dis[w]=-1;
return ok;
}
void Dfs(ll w){
dis[w]=1;
for (ll i=fa[w];i!=-1;i=g[i].next){
ll u=g[i].end;
if (dis[u]==-1&&g[i].c){
ci++;Dfs(u);
}
}
}
ll id(ll a,ll b){
return (a-1)*m+b;
}
int main()
{
while(scanf("%lld%lld",&n,&m)!=EOF){
S=0;T=n*m+1;
memset(fa,-1,sizeof(fa));tot=0;sum=0;ans=0;
for (ll i=1;i<=n;i++)
for (ll j=1;j<=m;j++){
scanf("%lld",&a);sum+=a;
if ((i+j)%2==0)add(S,id(i,j),a);
else add(id(i,j),T,a);
}
ll x,y;
for (ll i=1;i<=n;i++)
for (ll j=1;j<=m;j++)if ((i+j)%2==0){
z=id(i,j);
for (ll k=0;k<4;k++){
x=i+han[k];y=j+lie[k];
if (x>0&&x<=n&&y>0&&y<=m){
add(z,id(x,y),inf);
}
}
}
while (bfs()){
for (ll i=S;i<=T;i++)cur[i]=fa[i];
ans+=dfs(S,inf);
}
printf("%lld\n",sum-ans);
}
return 0;
}