HDu 1565格子取数(1)(最小割/状態圧縮+DP)
4162 ワード
Problem Description
n*nの格子の碁盤をあげて、各格子の中に非負の数があります.
任意の2つの数が存在する格子に共通のエッジがないように、いくつかの数を取り出します.つまり、取得した数が存在する2つの格子が隣接することができず、取得した数の和が最大になります.
Input
複数のテストインスタンスを含み、各テストインスタンスは1つの整数nとn*nの非負の数(n<=20)を含む.
Output
各テストインスタンスについて、取得可能な最大和を出力します.
Sample Input
Sample Output
2つの方法:
ポイントオーバーライドセット:図Gのポイントセットがなく、図中のすべてのエッジに少なくとも1つの端点がセット内にあるようにします.//最小ポイント権オーバーライドセット:ポイント権付き無方向図Gで、ポイント権の和が最小のオーバーライドセット.//ポイント独立セット:図Gの1つのポイントセットがなく、そのセット内の2つのポイントが元の図で隣接しないようにします.//最大点権独立セット:帯権無方向図Gにおいて、点権の和が最大の独立セット.//定理://1.最小ポイントオーバーライドセット=最小割合=最大ストリーム//2.最大ポイント独立セット=合計-最小ポイントオーバーライドセット
1 . 図全体について、座標と(x+y)が偶数の点を山に、座標と奇数の山に置く.図全体のため、座標と偶数の任意の2点は隣接していないので、座標と奇数のも同じです.
座標と偶数の点をソース点に接続し、容量は数値そのものです.座標と奇数の連結点であり、容量は数値そのものである.
各点について、上下左右の4つの点がつながっているので、この4つの点は隣接しているので、それを飲んで共存することはできません.容量はinfである.
構築されたネットワークを得た後、私たちはネットワークに対して最小の割合を求めることができて、切られた辺と最小、テーマが最大を求めるため、結果はsum-sap()です;
n*nの格子の碁盤をあげて、各格子の中に非負の数があります.
任意の2つの数が存在する格子に共通のエッジがないように、いくつかの数を取り出します.つまり、取得した数が存在する2つの格子が隣接することができず、取得した数の和が最大になります.
Input
複数のテストインスタンスを含み、各テストインスタンスは1つの整数nとn*nの非負の数(n<=20)を含む.
Output
各テストインスタンスについて、取得可能な最大和を出力します.
Sample Input
3
75 15 21
75 15 28
34 70 5
Sample Output
188
2つの方法:
ポイントオーバーライドセット:図Gのポイントセットがなく、図中のすべてのエッジに少なくとも1つの端点がセット内にあるようにします.//最小ポイント権オーバーライドセット:ポイント権付き無方向図Gで、ポイント権の和が最小のオーバーライドセット.//ポイント独立セット:図Gの1つのポイントセットがなく、そのセット内の2つのポイントが元の図で隣接しないようにします.//最大点権独立セット:帯権無方向図Gにおいて、点権の和が最大の独立セット.//定理://1.最小ポイントオーバーライドセット=最小割合=最大ストリーム//2.最大ポイント独立セット=合計-最小ポイントオーバーライドセット
1 . 図全体について、座標と(x+y)が偶数の点を山に、座標と奇数の山に置く.図全体のため、座標と偶数の任意の2点は隣接していないので、座標と奇数のも同じです.
座標と偶数の点をソース点に接続し、容量は数値そのものです.座標と奇数の連結点であり、容量は数値そのものである.
各点について、上下左右の4つの点がつながっているので、この4つの点は隣接しているので、それを飲んで共存することはできません.容量はinfである.
構築されたネットワークを得た後、私たちはネットワークに対して最小の割合を求めることができて、切られた辺と最小、テーマが最大を求めるため、結果はsum-sap()です;
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=450 ;
const int M=N*8 ;
const int inf = 1<<30;
struct node
{
int u,v,c,next;
}edge[M];
int pre[N],head[N],dis[N],cur[N],gap[N];
int top ;
int move[4][2]={0, 1, 0, -1, 1, 0, -1, 0};
void add(int u ,int v,int c)
{
edge[top].u=u;
edge[top].v=v;
edge[top].c=c;
edge[top].next=head[u];
head[u]=top++;
edge[top].u=v;
edge[top].v=u;
edge[top].c=0;
edge[top].next=head[v];
head[v]=top++;
}
int sap(int s,int t,int n)
{
int u,v,mindis,minflow=inf,flow=0;
memset(gap,0,sizeof(gap));
memset(dis,0,sizeof(dis));
memset(pre,-1,sizeof(pre));
for(int i=0;i<n;i++) cur[i]=head[i] ;
u=pre[s]=s;
gap[0]=n;
while(dis[s] <n)
{
loop:
for(int &i=cur[u] ; i!=-1 ; i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c && dis[u]==dis[v]+1)
{
pre[v]=u;
u=v;
if(minflow > edge[i].c)
minflow = edge[i].c ;
if(v==t)
{
for(u=pre[v] ; v!=s ; v=u,u=pre[u])
{
edge[cur[u]].c -=minflow ;
edge[cur[u]^1].c += minflow ;
}
flow +=minflow ;
minflow=inf;
}
goto loop ;
}
}
mindis=n;
for(int i=head[u];i!=-1 ; i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c>0 && dis[v] < mindis)
{
mindis=dis[v];
cur[u]=i;
}
}
if((--gap[dis[u]]) ==0) break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return flow ;
}
int main()
{
int n ,x ,sum;
while(~scanf("%d",&n))
{
top=0;sum=0;
memset(head,-1,sizeof(head));
int s=0,t=n*n+1 ;
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= n ; j++)
{
int tmp=(i-1)*n+j ;
scanf("%d",&x);
if((i+j)%2==0) //
add(s,tmp,x);
else
add(tmp,t,x) ;
sum+=x;
}
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= n ; j++)
if((i+j)%2==0) // ;
{
int tmp=(i-1)*n+j;
if(i>1) add(tmp,tmp-n,inf) ; // ;
if(i<n) add(tmp,tmp+n,inf) ;
if(j<n) add(tmp,tmp+1,inf) ;
if(j>1) add(tmp,tmp-1,inf) ;
}
int ans=sap(s,t,t+1);
printf("%d
",sum-ans) ;
}
return 0;
}