ZOJ3951 : Independent Set

如果知道了树的形态,那么可以树形DP,每个时刻只需要计算必选根的独立集个数以及必不选根的独立集个数。

那么现在知道独立集个数,要构造出树,可以考虑DP这棵树的形态,然后将之前树形DP的值作为现在DP的状态,即$dp[i][j]$表示必选根的独立集个数为$i$,必不选根的独立集个数为$j$时,树的节点数最少是多少。

那么完成这个DP之后,输出方案只需要沿着最优值来的顺序dfs输出即可。

 

#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<time.h>
#include<assert.h>
#include<iostream>
using namespace std;
typedef long long LL;
typedef pair<int,int>pi;
const int Inf=100;
int cnt;
int dp[2020][2020];
struct Node{
	short i,j,x,y;
	Node(){}
	Node(short i,short j,short x,short y):i(i),j(j),x(x),y(y){}
};
Node pre[2020][2020];
void dfs(int u,int x,int y){
	if(x==1&&y==1)return ;
	//printf("x=%d y=%d\n",x,y);
	dfs(u,pre[x][y].i,pre[x][y].j);
	++cnt;
	printf("%d %d\n",u,cnt);
	dfs(cnt,pre[x][y].x,pre[x][y].y);
}
vector<int>V[3000];
int main(){
	int tl=0;
	for(int i=1;i<=2005;i++){
		for(int j=i;j<=2005;j+=i)V[j].push_back(i);
	}
	for(int i=0;i<2020;i++)for(int j=0;j<2020;j++)dp[i][j]=Inf;
	dp[1][1]=1;
	for(int i=1;i<=2005;i++){
		for(int j=1;j<=2005;j++){
			if(dp[i][j]>15)continue;
			for(int y=1;y*i<=2005;y++){
				for(int x=1;(x+y)*j<=2005;x++){
					int tmp=dp[i][j]+dp[x][y];
					int nx=y*i,ny=j*(x+y);
					if(dp[nx][ny]>tmp){
						dp[nx][ny]=tmp;
						pre[nx][ny]=Node(i,j,x,y);
					}
					tl++;
				}
			}
			for(int y=1;y*(i+j)<=2005;y++){
				for(int x=1;x*j<=2005;x++){
					int tmp=dp[i][j]+dp[x][y];
					int nx=j*x,ny=y*(i+j);
					if(dp[nx][ny]>tmp){
						dp[nx][ny]=tmp;
						pre[nx][ny]=Node(x,y,i,j);
					}
					tl++;
				}
			}

		}
	}
	/*
	for(int nx=1;nx<=2005;nx++){
		for(int ny=1;ny<=2005;ny++){
			if(nx==1&&ny==1){dp[nx][ny]=1;continue;}
			for(int it1=0;it1<V[nx].size();it1++){
				for(int it2=0;it2<V[ny].size();it2++){
					int i=V[nx][it1],j=V[ny][it2];
					int y=nx/i,x=ny/j-y;
					if(x>=1&&y>=1&&dp[i][j]+dp[x][y]<dp[nx][ny]){
						dp[nx][ny]=dp[i][j]+dp[x][y];
						pre[nx][ny]=Node(i,j,x,y);
					}
					tl++;
				}
			}
		}
	}
	*/
	//printf("tl=%d\n",tl);
	int _;scanf("%d",&_);
	while(_--){
		int m;
		scanf("%d",&m);
	//for(int tm=1;tm<=2000;tm++){
	//	m=tm+1;
		m++;
		bool flag=0;
		int sx=-1,sy;
		for(int i=0;i<=m;i++){
			if(dp[i][m-i]<=15){
				sx=i;sy=m-i;
				break;
			}
		}
		if(sx<0)puts("-1");
		else{
			printf("%d\n",dp[sx][sy]);
			cnt=1;
			dfs(1,sx,sy);
		}
	}
	return 0;
}

  

posted @ 2017-04-09 22:55  Claris  阅读(274)  评论(0编辑  收藏  举报