您的位置:首页 > 其它

HDU 3360 奇偶染色建二分图 或者 拆点双边建二分图

2014-07-18 16:08 246 查看
方法一:

图中的点根据(i+j)%2为奇数或者偶数,划分为二分图,然后建图,直接求出二分最大匹配。

代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <queue>
using namespace std;
const int maxn=2505;
const int maxm=1000005;
struct EdgeNode
{
int to;
int next;
}edge[maxm];
int head[maxn],cnt;
void add(int x,int y)
{
edge[cnt].to=y;
edge[cnt].next=head[x];
head[x]=cnt++;
}

int n,m,v[maxn],pre[maxn];
int d[15][3]={{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,0},{0,1},{1,0},{0,-1}};
int g[maxn][maxn],jiou[maxn][maxn];

void init()
{
cnt=0;
memset(head,-1,sizeof(head));
}

int dfs(int x)
{
int y;
for(int i=head[x];i!=-1;i=edge[i].next)
{
y=edge[i].to;
if(!v[y]){
v[y]=1;
if(!pre[y]||dfs(pre[y])){
pre[y]=x;
return true;
}
}
}
return false;
}

int erfenpipei()
{
int sum=0;
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++){
memset(v,0,sizeof(v));
if(dfs(i))
sum++;
}
return sum;
}

int yj(int x,int y)
{
if(x<1||x>n||y<1||y>m)return 1;
return 0;
}

int main()
{
int i,j,x,y,l,s,t,k,cs=0,vx,vy;
while(~scanf("%d%d",&n,&m)&&(n+m))
{
cs++;
init();
vx=vy=0;
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
scanf("%d",&g[i][j]);
if((i+j)%2)jiou[i][j]=++vx; //奇偶染色
else jiou[i][j]=++vy;
}
}
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
if(g[i][j]!=-1){
l=0; k=g[i][j];
while(k){
if(k%2){
x=i+d[l][0]; y=j+d[l][1];
if(g[x][y]!=-1&&!yj(x,y)){
s=jiou[i][j]; t=jiou[x][y];
if((i+j)%2==0)swap(s,t);
add(s,t);
}
}
k=k/2;
l++;
}
}
}
}
n=max(vx,vy);
n=erfenpipei();
printf("%d. %d\n",cs,n);
}
return 0;
}


方法二:

图中所有的点为1~n*m,将其拆成两份,为每一对看守关系建立双边,求出最大匹配/2。

代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <queue>
using namespace std;
const int maxn=2505;
const int maxm=1000005;
struct EdgeNode
{
int to;
int next;
}edge[maxm];
int head[maxn],cnt;
void add(int x,int y)
{
edge[cnt].to=y;
edge[cnt].next=head[x];
head[x]=cnt++;
}

int n,m,v[maxn],pre[maxn];
int d[15][3]={{-1,-2},{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,0},{0,1},{1,0},{0,-1}};
int g[maxn][maxn];

void init()
{
cnt=0;
memset(head,-1,sizeof(head));
}

int dfs(int x)
{
int y;
for(int i=head[x];i!=-1;i=edge[i].next)
{
y=edge[i].to;
if(!v[y]){
v[y]=1;
if(!pre[y]||dfs(pre[y])){
pre[y]=x;
return true;
}
}
}
return false;
}

int erfenpipei()
{
int sum=0;
memset(pre,0,sizeof(pre));
for(int i=1;i<=n;i++){
memset(v,0,sizeof(v));
if(dfs(i))
sum++;
}
return sum;
}

int yj(int x,int y)
{
if(x<1||x>n||y<1||y>m)return 1;
return 0;
}

int main()
{
int i,j,x,y,l,s,t,k,cs=0;
while(~scanf("%d%d",&n,&m)&&(n+m))
{
cs++;
init();
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
scanf("%d",&g[i][j]);
}
}
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
if(g[i][j]!=-1){
l=0; k=g[i][j];
while(k){
if(k%2){
x=i+d[l][0]; y=j+d[l][1];
if(g[x][y]!=-1&&!yj(x,y)){
s=(i-1)*m+j; t=(x-1)*m+y;
add(s,t);
add(t,s);
}
}
k=k/2;
l++;
}
}
}
}
n=n*m;
n=erfenpipei()/2;
printf("%d. %d\n",cs,n);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二分匹配