利用最大流求权值。。
对于此棋盘应进行黑白染色,相邻元素其权值为无穷大,
源点到白棋的权值为白棋的值,黑棋到汇点的权值为黑棋的值。
然后建立通路求出最大流。。。
#include"stdio.h"
#include"string.h"
#include"queue"
#define inf 0x7fffffff
using namespace std;
int r[300][300];
int pre[300],p[1000];
int visit[300];
int n,m,h;
int bfs(int s,int t)
{
int p,i;
queue<int>q;
memset(visit,0,sizeof(visit));
memset(pre,0,sizeof(pre));
pre[s]=s;
visit[s]=1;
q.push(s);
while(!q.empty())
{
p=q.front();
q.pop();
for(i=0;i<=h;i++)
{
if(visit[i]==0&&r[p][i])
{
pre[i]=p;
visit[i]=1;
if(i==t)
return 1;
q.push(i);
}
}
}
return 0;
}
int EK(int s,int t)
{
int d,i,flow=0;
while(bfs(s,t))
{
d=inf;
for(i=t;i!=s;i=pre[i])
d=d<r[pre[i]][i]?d:r[pre[i]][i];
for(i=t;i!=s;i=pre[i])
{
r[pre[i]][i]-=d;
r[i][pre[i]]+=d;
}
flow+=d;
}
return flow;
}
int main()
{
int i,sum;
while(scanf("%d",&n)!=EOF)
{
memset(r,0,sizeof(r));
memset(p,0,sizeof(p));
sum=0;
h=n*n+1;
for(i=1;i<=n*n;i++)
{
scanf("%d",&m);
sum+=m;
if(i<=n)
p[i]=(p[i-1]+1)%2;
else
p[i]=(p[i-n]+1)%2;
if(p[i]==1)
{
if(i%n!=1)//非行首元素。
r[i][i-1]=inf;
if(i%n!=0)//非行末元素
r[i][i+1]=inf;
if(i<=n*(n-1))//非最后一行元素
r[i][i+n]=inf;
if(i>n)//非第一行元素
r[i][i-n]=inf;
r[0][i]=m;
}
else
r[i][h]=m;
}
printf("%d\n",sum-EK(0,h));
}
return 0;
}
p值为一是白棋,0的为黑棋。
此题的图是:
源点0—》白棋——》黑棋——》汇点(n*n+1);
点覆盖集:无向图G的一个点集,使得该图中所有边都至少有一个端点在该集合内。
最小点权覆盖集:在带点权无向图G中,点权之和最小的覆盖集。
点独立集:无向图G的一个点集,使得任两个在该集合中的点在原图中都不相邻。
最大点权独立集:在带权无向图G中,点权之和最大的独立集。
定理:
1. 最小点权覆盖集=最小割=最大流
2. 最大点权独立集=总权-最小点权覆盖集
解题:
1. 先染色,取一个点染白色,和它相邻的点染黑色
2. 每个白点向它相邻的黑点连一条边,容量为 inf (无穷大)
3. 增加源点S,向每一个白色点连一条边,容量为白点的权
4. 增加汇点T,每个黑点向T连一条边,容量为黑点的权
#include"stdio.h"
#include"string.h"
int s[1<<21];
int map[22][22];
int dp[3][1<<21];
int max(int a,int b)
{
return a>b?a:b;
}
int ok(int x)记录可行状态
{
if(x&x>>1)
return 0;
return 1;
}
int main()
{
int n,m,i,j,k,h,p,sum;
while(scanf("%d",&n)!=EOF)
{
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&map[i][j]);
k=0;
for(i=0;i<(1<<n);i++)
{
if(ok(i))
s[k++]=i;
}
p=0;
for(i=0;i<n;i++)
{
p=p^1;///进行滚动数组
for(j=0;j<k;j++)枚举每行的所有状态
{
sum=0;
for(h=0;h<n;h++)
if(s[j]&(1<<h))
sum+=map[i][h];记录该状态值
for(h=0;h<k;h++)//枚举已经得到的状态转移到该状态能到的最大值
{
if((s[j]&s[h])==0)
dp[p][s[j]]=max(dp[p][s[j]],dp[1-p][s[h]]+sum);
}
}
}
int ans=0;
for(i=0;i<k;i++)
ans=max(ans,dp[p][s[i]]);
printf("%d\n",ans);
}
return 0;
}
dinic 算法
#include"stdio.h" #include"string.h" #define inf 0x7fffffff #define M 2000 int n,s,t,adj[M],dis[M]; int q[M],p[M],sum; struct point { int v,u; int flow,next; }map[M]; int min(int a,int b) { a=a>b?b:a; return a; } void insert(int u,int v,int w) { map[sum].u=u,map[sum].v=v,map[sum].flow=w,map[sum].next=adj[u]; adj[u]=sum;sum++; map[sum].u=v,map[sum].v=u,map[sum].flow=0,map[sum].next=adj[v]; adj[v]=sum;sum++; } int bfs() { int i,x,v,tail=0,head=0; memset(dis,0,sizeof(dis)); dis[s]=1; q[tail++]=s; while(head<tail) { x=q[head++]; for(i=adj[x];i!=-1;i=map[i].next) { v=map[i].v; if(map[i].flow&&dis[v]==0) { dis[v]=dis[x]+1; if(v==t) return 1; q[tail++]=v; } } } return 0; } int dfs(int s,int limit) { if(s==t) return limit; int i,temp,cost=0,v; for(i=adj[s];i!=-1;i=map[i].next) { v=map[i].v; if(map[i].flow&&dis[s]==dis[v]-1) { temp=dfs(v,min(limit-cost,map[i].flow)); if(temp>0) { map[i].flow-=temp; map[i^1].flow+=temp; cost+=temp; if(limit==cost) break; } else dis[v]=-1; } } return cost; } int dinic() { int ans=0; while(bfs()) { ans+=dfs(s,inf); } return ans; } int main() { int i,k,ss; while(scanf("%d",&n)!=EOF) { memset(adj,-1,sizeof(adj)); memset(p,0,sizeof(p)); s=0,sum=0;t=n*n+1;ss=0; for(i=1;i<=n*n;i++) { scanf("%d",&k); ss+=k; if(i>n) p[i]=(p[i-n]+1)%2; else p[i]=(p[i-1]+1)%2; if(p[i]==1) { insert(0,i,k); if(i%n!=1) insert(i,i-1,inf); if(i%n!=0) insert(i,i+1,inf); if(i>n) insert(i,i-n,inf); if(i<=n*(n-1)) insert(i,i+n,inf); } else insert(i,t,k); } printf("%d\n",ss-dinic()); } return 0; }