E. Graph Coloring(二分圖+分組揹包)

E. Graph Coloring(二分圖+分組揹包)

傳送門

思路:將每個二分子圖看作一組,兩部分的結點看成兩個物品,首先判斷每個子圖是不是都爲二分圖,若不是則無解,因爲1和3等價,所以只需要對11和2進行染色判斷,然後再用分組揹包,看能否恰好裝下體積爲n2n_2的物品。

因爲要輸出分案,所以需要一個數組來進行回溯記錄路徑。回溯的時候判斷一下前一個路徑點的物品數是來自於1,還是來自於2即可。

時間複雜度O(n2)O(n^2)

AC代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e3+10,M=1e5+5;
#define mst(a) memset(a,0,sizeof a)
struct edge{
	int to,nt;
}e[M<<1];
int col[N],n,m,f[N][N],cnt[N][3],bl[N],id,tot=1,h[N],n1,n2,n3,path[N];//id表示二分子圖編號,bl[i]表示結點i屬於那個二分子圖 
void add(int u,int v){//col[i]結點i的顏色 f[i][j]第i組染色後有j個n2被染色. 
	e[tot]={v,h[u]};
	h[u]=tot++;
}
void dfs(int u,int c){ //染色法判斷二分圖 
	col[u]=c,bl[u]=id,cnt[id][c]++;
	for(int i=h[u];i;i=e[i].nt){
		int v=e[i].to;
		if(col[v]==col[u]){
			puts("NO");
			exit(0);
		}
		if(!col[v]) dfs(v,3-c);
	}
} 
int main(){
	scanf("%d%d%d%d%d",&n,&m,&n1,&n2,&n3);
	for(int i=1,u,v;i<=m;i++){
		scanf("%d%d",&u,&v);
		add(u,v),add(v,u);
	}
	f[0][0]=1;//初始化 
	for(int i=1;i<=n;i++){
		 if(col[i]) continue;
		 id++;
		 dfs(i,1);
		 for(int j=cnt[id][1];j<=n2;j++)   //分組揹包dp 
		 	 f[id][j]|=f[id-1][j-cnt[id][1]];
		 for(int j=cnt[id][2];j<=n2;j++)
			 f[id][j]|=f[id-1][j-cnt[id][2]];
	}
	if(!f[id][n2]){
		puts("NO");
		return 0; 
	}
	puts("YES");
	 while(id){  //回溯記錄路徑 
	 	 path[id]=f[id-1][n2-cnt[id][1]];
	 	 if(path[id]) n2-=cnt[id][1];
	 	 else n2-=cnt[id][2];
	 	 id--;
	 } 
	 for(int i=1;i<=n;i++){
	 	if(path[bl[i]]) col[i]=3-col[i];
		if(col[i]==2) printf("2");
		else if(n1>0) printf("1"),n1--;
		else printf("3");
	 }
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章