1. 程式人生 > 實用技巧 >AtCoder Beginner Contest 187 F - Close Group(狀態壓縮動態規劃)

AtCoder Beginner Contest 187 F - Close Group(狀態壓縮動態規劃)

差億點AK,只怪沒學過狀態壓縮動態規劃,呀嘞呀嘞dazei
列舉一個圖的子圖:

for(int i=n;i;i=(i-1)&n)
{
      //i就是n的子圖
}

AtCoder Beginner Contest 187 F - Close Group

題意:給一個n(n<=18)節點m條邊的圖,刪除幾個邊後,使它變成幾個連通子圖,求最少能夠變成幾個子圖,並且全是完全圖
題解:首先列舉所有子圖,如果是完全圖,標記dp[i]=1,然後從小到大列舉,對一個非完全子圖,再列舉其子圖更新答案,由於是從小到大列舉,因此當前子圖的子圖肯定已經更新完了,所以可放心dp

#include<bits/stdc++.h>
using namespace std;
#define f(i,a,b) for(register int i=a;i<=b;++i)
#define ll long long
#define pb push_back
inline int read(){int x;scanf("%d",&x);return x;}
int eg[20][20],dp[1<<N];
void solve()
{
	int n=read(),m=read();
	f(i,1,m){
		int x=read(),y=read();
		eg[x][y]=eg[y][x]=1;
	}
	int sum=(1<<n)-1;
	dp[0]=999999;
	for(int i=1;i<=sum;++i)
	{
		vector<int>edge;
		for(int j=0;j<n;j++) if(i&(1<<j)) edge.pb(j+1);
		int flag=1;
		for(int j=0;flag&&j<edge.size();++j)
			for(int k=j+1;flag&&k<edge.size();++k)
				if(!eg[edge[j]][edge[k]]) flag=0;
		if(flag) dp[i]=1;
		else dp[i]=999999; 
	}
	for(int i=1;i<=sum;++i)
	{
		if(dp[i]==1) continue;
		for(int j=i;j;j=(j-1)&i)
		{
			dp[i]=min(dp[i],dp[j]+dp[j^i]);
		}
	}
	cout<<dp[sum]<<endl;
}
int main()
{
	int T=1;
	while(T--) solve();
	return 0;
}