ネットワーク・フローの最小ポイント権オーバーライドと最大ポイント権独立セット
ネットワーク・フローの最小ポイント権最大ポイント権独立セットを上書き
二分図の最小点オーバーライドと最大独立セットは、最大マッチング解に変換できます.これに基づいて,各点に非負の重み値を与えると,この2つの問題は,二分図最小点重みオーバーライドと二分図最大点重み独立セットに変換される.
二分図最小点重みオーバーライド
xまたはyのセットからいくつかの点を選択し、これらの点がすべてのエッジを上書きし、選択された点の重み値ができるだけ小さくなります.
モデリング:
元の二分図のエッジ(u,v)をINF容量の有向エッジ(u,v)に置き換え、ソースポイントsとシンクポイントtを設定し、sとx集合のポイントを接続し、容量はそのポイントの重み値である.y中の点をtに接続し、容量はその点の重み値である.新しい図の上で最大の流れを求めて、最大の流量はつまり最小の点の重みのカバーする重みの値とです.
二分図最大ポイント独立セット
重み値と最大のポイントセットが二分図に表示され、両者の間にエッジがないようになります.実はそれは最小点権がカバーする対偶問題です.答え=総重み-最小点オーバーライドセット.具体的な証明は胡波濤の論文を参考にする.
例:HDU 1569
タイトル:m*nの碁盤で、各格子には重み値があり、そこからいくつかの数を取り出し、任意の2つの数が存在する格子に共通のエッジがなく、取り出された数と最大になる.この最大の値を求めます.
解:
格子を二分図に染色することは,明らかに二分図の最大点権独立セットを求めることである.問題を二分図最小点重みオーバーライドに変換して解き,最終結果=総重みと−最大ストリームである.
二分図の最小点オーバーライドと最大独立セットは、最大マッチング解に変換できます.これに基づいて,各点に非負の重み値を与えると,この2つの問題は,二分図最小点重みオーバーライドと二分図最大点重み独立セットに変換される.
二分図最小点重みオーバーライド
xまたはyのセットからいくつかの点を選択し、これらの点がすべてのエッジを上書きし、選択された点の重み値ができるだけ小さくなります.
モデリング:
元の二分図のエッジ(u,v)をINF容量の有向エッジ(u,v)に置き換え、ソースポイントsとシンクポイントtを設定し、sとx集合のポイントを接続し、容量はそのポイントの重み値である.y中の点をtに接続し、容量はその点の重み値である.新しい図の上で最大の流れを求めて、最大の流量はつまり最小の点の重みのカバーする重みの値とです.
二分図最大ポイント独立セット
重み値と最大のポイントセットが二分図に表示され、両者の間にエッジがないようになります.実はそれは最小点権がカバーする対偶問題です.答え=総重み-最小点オーバーライドセット.具体的な証明は胡波濤の論文を参考にする.
例:HDU 1569
タイトル:m*nの碁盤で、各格子には重み値があり、そこからいくつかの数を取り出し、任意の2つの数が存在する格子に共通のエッジがなく、取り出された数と最大になる.この最大の値を求めます.
解:
格子を二分図に染色することは,明らかに二分図の最大点権独立セットを求めることである.問題を二分図最小点重みオーバーライドに変換して解き,最終結果=総重みと−最大ストリームである.
/*
:
, = -
:
s t,s i, i ; j t, j ; INF, 。
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int INF = 0x7fffffff;
const int maxv = 2600;
const int maxe = 1000000;
int n,m;
int g[55][55];
struct Edge
{
int v;
int next;
int flow;
};
Edge e[maxe];
int head[maxv],edgeNum;
int now[maxv],d[maxv],vh[maxv],pre[maxv],preh[maxv];
int start,end;
void addEdge(int a,int b,int c)
{
e[edgeNum].v = b;
e[edgeNum].flow = c;
e[edgeNum].next = head[a];
head[a] = edgeNum++;
e[edgeNum].v = a;
e[edgeNum].flow = 0;
e[edgeNum].next = head[b];
head[b] = edgeNum++;
}
void Init()
{
edgeNum = 0;
memset(head,-1,sizeof(head));
memset(d,0,sizeof(d));
}
int sap(int s,int t,int n) // , ,
{
int i,x,y;
int f,ans = 0;
for(i = 0; i < n; i++)
now[i] = head[i];
vh[0] = n;
x = s;
while(d[s] < n)
{
for(i = now[x]; i != -1; i = e[i].next)
if(e[i].flow > 0 && d[y=e[i].v] + 1 == d[x])
break;
if(i != -1)
{
now[x] = preh[y] = i;
pre[y] = x;
if((x=y) == t)
{
for(f = INF,i=t; i != s; i = pre[i])
if(e[preh[i]].flow < f)
f = e[preh[i]].flow;
ans += f;
do
{
e[preh[x]].flow -= f;
e[preh[x]^1].flow += f;
x = pre[x];
}while(x!=s);
}
}
else
{
if(!--vh[d[x]])
break;
d[x] = n;
for(i=now[x]=head[x]; i != -1; i = e[i].next)
{
if(e[i].flow > 0 && d[x] > d[e[i].v] + 1)
{
now[x] = i;
d[x] = d[e[i].v] + 1;
}
}
++vh[d[x]];
if(x != s)
x = pre[x];
}
}
return ans;
}
void build()
{
int i,j;
for(i = 1; i <= m; i++)
{
for(j = 1; j <= n; j++)
{
int t = (i-1)*n+j;
if((i+j)%2)
{
addEdge(start,t,g[i][j]);
if(i>1)
addEdge(t,t-n,INF);
if(i<m)
addEdge(t,t+n,INF);
if(j>1)
addEdge(t,t-1,INF);
if(j<n)
addEdge(t,t+1,INF);
}
else
addEdge(t,end,g[i][j]);
}
}
}
int main()
{
int i,j;
int result;
while(scanf("%d %d",&m,&n) != EOF)
{
result = 0;
Init();
for(i = 1; i <= m; i++)
{
for(j = 1; j <= n; j++)
{
scanf("%d",&g[i][j]);
result += g[i][j];
}
}
start = 0;
end = n*m + 1;
build();
printf("%d
",result-sap(start,end,end+1));
}
return 0;
}