hdu5556 2015ACM合肥现场赛题 二分图最大独立集

21 篇文章 0 订阅
10 篇文章 0 订阅

题意

  • 在一个n*m的矩阵中,标记为’.’的为单独的一个点,标记为同一个数字的单元格和在一起是一个点,且是四联通的,为你这样建图之后它的最大独立集。
  • n,m <= 10,数字数是0~9

思路

  • 枚举0~9哪些放入独立集中,这样有2^10的复杂度
  • 在上述的基础上,建立二分图,具体来说,是数字格的单元格不作为二分图的点加入,是放入独立集的数字格周围的单元格不算做二分图里的点。
  • 剩余的点,i+j 是奇数的作为一个集合,i+j为偶数的是另一个集合
  • 这里我用最大流解解决的最大独立集。
  • 吐槽:真是各种T,各种剪枝。。。终于g++过了。。。c++还在T中。。。

实现

#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstdio> 
#include <vector>
#include <map>
using namespace std;

typedef pair<int,int> pii;
#define fi first
#define se second
#define mp make_pair 
#define pb push_back

const int MAXM = 500;
const int MAXN = 12;
const int maxn = 105;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to,next,cap,flow;
}edge[MAXM];
int tol;
int head[maxn];
int gap[maxn],dep[maxn],pre[maxn],cur[maxn];
void init()
{
    tol = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw = 0)
{
    edge[tol].to = v;
    edge[tol].cap = w;
    edge[tol].next = head[u];
    edge[tol].flow = 0;
    head[u] = tol++;
    edge[tol].to = u;
    edge[tol].cap = rw;
    edge[tol].next = head[v];
    edge[tol].flow = 0;
    head[v] = tol++;
}
int sap(int start,int end,int N)
{
    memset(gap,0,sizeof(gap));
    memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(head));
    int u = start;
    pre[u] = -1;
    gap[0] = N;
    int ans = 0;
    while(dep[start] < N)
    {
        if(u == end)
        {
            int Min = INF;
            for(int i = pre[u]; i != -1;i = pre[edge[i^1].to])
                if(Min > edge[i].cap - edge[i].flow)
                    Min = edge[i].cap - edge[i].flow;
            for(int i = pre[u];i != -1;i = pre[edge[i^1].to])
            {
                edge[i].flow += Min;
                edge[i^1].flow -= Min;
            }
            u = start;
            ans += Min;
            continue;
        }
        bool flag = false;
        int v;
        for(int i = cur[u];i != -1;i = edge[i].next)
        {
            v = edge[i].to;
            if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])
            {
                flag = true;
                cur[u] = pre[v] = i;
                break;
            }
        }
        if(flag)
        {
            u = v;
            continue;
        }
        int Min = N;
        for(int i = head[u];i != -1;i = edge[i].next)
            if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
            {
                Min = dep[edge[i].to];
                cur[u] = i;
            }
        gap[dep[u]]--;
        if(!gap[dep[u]])return ans;
        dep[u] = Min+1;
        gap[dep[u]]++;
        if(u != start)u = edge[pre[u]^1].to;
    }
    return ans;
}
//the end of 最大流部分





char diTu[MAXN][MAXN];
int mark[MAXN][MAXN];
int mark_now[MAXN][MAXN];
int id[MAXN][MAXN];
pii rid[maxn];
int g[maxn][maxn];
int vec[10];
pii d[4];
//点数 
int num;
int id2[MAXN][MAXN];

int n_p;
int yingShe[10];
map<char,int> mapp;

bool judge(int s){
    int ss = s;
    for (int i=0;ss>0;i++,ss>>=1){
        if ((ss&1) == 0){
            continue;
        }
        for (int j=0;j<n_p;j++){
            if (s & (1<<j)){
                if (g[yingShe[i]][yingShe[j]]){
                    return false;
                }
            }
        }       
    }

    return true;
} 



int main(){
    int T;
    d[0] = mp(0,1);
    d[1] = mp(0,-1);
    d[2] = mp(1,0);
    d[3] = mp(-1,0);

    cin>>T;
    for (int t=1;t<=T;t++){
        int n,m;
        n_p = 0;

        memset(mark,0,sizeof(mark));
        memset(g,0,sizeof(g));
        memset(vec,0,sizeof(vec));
        num = 10;   
        mapp.clear();
        mapp['.'] = 1;

        scanf("%d%d",&n,&m);
        for (int i=0;i<n;i++){
            getchar();
            for (int j=0;j<m;j++){
                diTu[i][j] = getchar();
                if (diTu[i][j] == '.'){
                    id[i][j] = num;
                    rid[num] = mp(i,j);
                    num++;
                }
                else{
                    vec[diTu[i][j] - '0']++;
                    id[i][j] = diTu[i][j] - '0';
                    mark[i][j] = 1;
                }
            }
        }

        for (int i=0;i<n;i++){
            for (int j=0;j<m;j++){
                if (mapp[diTu[i][j]] == 0){
                    yingShe[n_p] = diTu[i][j] - '0';
                    mapp[diTu[i][j]] = 1;
                    n_p ++;
                }
            }
        }

        for (int i=0;i<n;i++){
            for (int j=0;j<m;j++){
                int x = i;
                int y = j;
                for (int k=0;k<4;k++){
                    int x1 = x + d[k].fi;
                    int y1 = y + d[k].se;
                    if (x1 >= n || x1 < 0 || y1 >= m || y1 < 0){
                        continue;
                    }
                    g[id[x][y]][id[x1][y1]] = 1;
                    g[id[x1][y1]][id[x][y]] = 1;
                }
            }
        }

        for (int i=0;i<num;i++){
            g[i][i] = 0;
        } 

        int ans = 0;
        for (int s=0;s<(1<<n_p);s++){
            if (judge(s) == false)
                continue;
            int pren = 0;
            int tmp = 0;
            memcpy(mark_now,mark,sizeof(mark));
            memset(id,0,sizeof(id));
            init();

            int ss = s;
            for (int i=0;ss>0;i++,ss>>=1){
                if ((ss&1) == 0 || vec[yingShe[i]] == 0){
                    continue;
                }
                pren++;
                for (int j=10;j<num;j++){
                    if (g[yingShe[i]][j]){
                        int x = rid[j].fi;
                        int y = rid[j].se;
                        mark_now[x][y] = 1;
                    }
                }

            }
            tmp = pren;

            int sum = 0;
            for (int i=0;i<n;i++){
                for (int j=0;j<m;j++){
                    sum += (mark_now[i][j] ^ 1);
                }
            }

            int now = 1;

            for (int i=0;i<n;i++){
                for (int j=0;j<m;j++){
                    if (mark_now[i][j] == 1){
                        continue;
                    }
                    if (i+j & 1){
                        if (id[i][j] != 0)
                            addedge(id[i][j],sum+1,1);
                        else{
                            addedge(now,sum+1,1);
                            id[i][j] = now;
                            now++;
                        }       
                    }
                    else{   
                        addedge(0,now,1);
                        id[i][j] = now;
                        now++;
                        int pre = now - 1;
                        for (int k=0;k<4;k++){
                            int x = i + d[k].fi;
                            int y = j + d[k].se;
                            if (x >= n || x < 0 || y >= m || y < 0){
                                continue;
                            }
                            if (mark_now[x][y] != 0){
                                continue;
                            }
                            if (id[x][y] != 0){
                                addedge(pre,id[x][y],1);
                            }
                            else{
                                addedge(pre,now,1);
                                id[x][y] = now;
                                now++;
                            }   
                        }
                    }

                }
            }


            tmp += sum - sap(0,sum+1,sum+2);
            ans = max(ans,tmp);
        }

        printf("Case #%d: %d\n",t,ans);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值