[Tjoi2013]攻击装置 bzoj3175 独立集与特例

本文探讨了无向图中最大独立集的求解方法,特别针对树和二分图给出了多项式时间内的解决方案。对于树,通过动态规划实现O(N)的时间复杂度;对于二分图,利用匹配算法计算最大独立集大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

独立集。

对于一个无向图,要求他的最大独立集,这是个npc问题,无法在多项式时间内得出答案,退而求其次,我们只能找到一些特殊图的最大独立集的多项式解法。

1.树。

   这是一个比较好求的,有两种办法,一种是贪心,一种是动归,都是O(N)的,贪心暂时不会,也没准备会,动归简单:f[i][0]表示第i个不取,他与他的儿子得到的最大答案,f[i][1]表示第i个要取,他与他的儿子得到的最大答案。

  f[i][0]=sum{max{f[son[i]][0],f[son[i]][1]}};

  f[i][1]=sum{f[son[i]][0]}+1;

2.二分图。

  这个也好求,ans=总点数-最大匹配数。

  做一遍二分图匹配就行了。

 

#include <cstdio> 
#include <cstring> 
#include <cstdlib> 
#include <cmath> 
#include <ctime> 
#include <iostream> 
#include <algorithm>
#define maxn 1000020
using namespace std;
int n;
char st[2000][200];
int x[8]={-1,-2,1,2,-1,-2,1,2};
int y[8]={-2,-1,-2,-1,2,1,2,1};

int tot=1;
int fir[maxn],en[maxn],nex[maxn],f[maxn];
inline void ins(int x,int y,int z){
//	printf("%d %d %d\n",x,y,z);
	nex[++tot]=fir[x];
	fir[x]=tot;
	en[tot]=y;
	f[tot]=z;
	
	nex[++tot]=fir[y];
	fir[y]=tot;
	en[tot]=x;
	f[tot]=0;
}

int s,t;
int flog=0,sum=0;
int now[maxn],pre[maxn],his[maxn],num[maxn],d[maxn];
inline void sap(){
    flog=0;
    for (int i=0;i<=t;i++){
        now[i]=fir[i];
        num[i]=d[i]=0;
        }
    num[0]=sum;
    int i=s;
    bool flag;
    int aug=0x7fffffff/10;
    while (d[s]<sum){
        flag=false;
        his[i]=aug;
        for (int k=now[i];k;k=nex[k]){
            int j=en[k];
            if ((d[i]==d[j]+1)&&(f[k]>0)){
                now[i]=k;
                pre[j]=i;
                flag=true;
                if (aug>f[k]) aug=f[k];
                i=j;
                if (i==t){
                    flog+=aug;
                    while (i!=s){
                        i=pre[i];
                        f[now[i]]-=aug;
                        f[now[i]^1]+=aug;
                        }
                    aug=0x7fffffff/10;
                    }
                break;
                }
            }
        if (flag) continue;
        int k1=0,minn=sum;
        for (int k=fir[i];k;k=nex[k])
            if (f[k]>0&&minn>d[en[k]]){
                minn=d[en[k]];
                k1=k;
                }
        --num[d[i]];
        if (num[d[i]]==0) return;
        d[i]=minn+1;
        ++num[d[i]];
        now[i]=k1;
        if (i!=s){
            i=pre[i];
            aug=his[i];
            }
        } 
}
int main(){
//	freopen("3175.in","r",stdin);
//	freopen("3175.out","w",stdout);
	scanf("%d\n",&n);
	for (int i=1;i<=n;i++){
		for (int j=1;j<=n;j++){
			scanf("%c",&st[i][j]);
			if (st[i][j]=='0')
				sum++;
			}
		getchar();
		}
	
	s=0;t=n*n+1;
	sum=sum+2;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			if (st[i][j]=='0'){
				if ((i+j)%2==1){
					ins(s,(i-1)*n+j,1);
					for (int p=0;p<8;p++)
						if (i+x[p]>=1&&i+x[p]<=n)
						if (j+y[p]>=1&&j+y[p]<=n)
						if (st[i+x[p]][j+y[p]]=='0')
							ins((i-1)*n+j,(i+x[p]-1)*n+j+y[p],0x7fffffff/10);
					}
				else ins((i-1)*n+j,t,1);
				}
	sap();
	printf("%d",sum-2-flog);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值