首页 > 代码库 > HDU 4892 状压dp

HDU 4892 状压dp


[BestCoder Round #5]冠军的奖励是小米3手机一部
恭喜福州大学杨楠获得[BestCoder Round #4]冠军(iPad Mini一部)
《BestCoder用户手册》下载

Defence of the Trees

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 224    Accepted Submission(s): 51
Special Judge


Problem Description
There are n trees (each of them can be considered as a point) on a two-dimensional coordinate system. There are k categories of trees, category of the ith tree are represented by Ai. There are also m stumps (each of them can be considered as a point, too) on this two-dimensional coordinate system. Stumps can be connected with straight wires.

Your task is to connect some of the stumps by wires to build exactly one simple polygon (that is, a polygon without self-intersection and degeneration) which contains trees of all k categories inside. Meanwhile, in order to save money, you should make the total length of wires as short as possible. Your task is to calculate the shortest total length of wires, or to determine that there is no solutions.
 

Input
There are several testcases, please process till EOF.

In each testcases:
First one line, three numbers n, m, k. Following n lines contains n 2D-coordinates describing each tree. Next one line contains n number, where ith number Ai denotes ith tree‘s category. Next m lines describe the coordinates of stumps, you may assume that there is no trees lying on segments between any two stumps.

All input will be integer, and absolute value of them will be less than 23333, 1 ≤ n ≤ 300, 1 ≤ m ≤ 40, 1 ≤ k ≤ 6,1 ≤ Ai ≤ k.In about 90% of testcases,m ≤ 10.
 

Output
For each testcase, print one line, if there is no solutions, Output "Impossible" (without quotes), else output a real number indicating the minimal total length. Your answer will be considered correct if and only if the absolute error or relative error are less than 10-6.
 

Sample Input
2 4 1 0 0 2 0 1 1 1 -1 1 1 -3 -1 5 1 2 4 2 0 0 2 0 1 2 1 -1 1 1 -3 -1 5 1
 

Sample Output
10.472135955000 16.944271909999
 

Author
Fudan University

题意:

有n颗树,总共有k种种类,每棵树有一个种类,有m个木桩,要选一些木桩连起来,使得包含所有的树的种类,并且连线最短。

由于k<=6,数据很小,一看就是状压dp, 把m个点的三角形全部找出来,然后把三角形内部k个种类的状态全部找出来,然后就是三角形合并,每次合并都会是

两边的周长减去公共边的长度的2倍,然后状态合并,

用类似与最短路的方法求答案。

搞了半天,发现spfa有问题,我们需要记录k的状态,还需要记录当前周长的状态,由于一个状态可能有多个周长,用数组记录也不大方便,所以把它拧成一个节点,丢进优先队列里,这样合并就没问题了,

代码:

/* ***********************************************
Author :rabbit
Created Time :2014/8/15 10:13:28
File Name :5.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 1e15
#define eps 1e-9
#define pi acos(-1.0)
typedef long long ll;
int dcmp(double x){
	if(fabs(x)<eps)return 0;
	return x>0?1:-1;
}
struct Point{
	double x,y;
	Point(double _x=0,double _y=0){
		x=_x;
		y=_y;
	}
};
Point operator + (Point a,Point b){
	return Point(a.x+b.x,a.y+b.y);
}
Point operator - (Point a,Point b){
	return Point(a.x-b.x,a.y-b.y);
}
double dist(Point a,Point b){
	double ss=a.x-b.x;
	double tt=a.y-b.y;
	return sqrt(ss*ss+tt*tt);
}
double Cross(Point a,Point b){
	return a.x*b.y-a.y*b.x;
}
int tot,id[40][40][40],state[11010];
int getid(int a,int b,int c){
	if(b>c)swap(b,c);
	if(a>b)swap(a,b);
	if(b>c)swap(b,c);
	return id[a][b][c];
}
int head[11010],tol;
struct Edge{
	int next,to;
	double val;
}edge[2002000];
void addedge(int u,int v,double val){
	edge[tol].to=v;
	edge[tol].val=val;
	edge[tol].next=head[u];
	head[u]=tol++;
}
double dp[11010][1<<6];
int vis[10010][1<<6];
Point p1[400],p2[400];
int dd[500];
double A[100100];
bool check(Point a,Point b,Point c,Point d){
	double t1=fabs(Cross(a-d,b-d));
	double t2=fabs(Cross(a-d,c-d));
	double t3=fabs(Cross(b-d,c-d));
	double t4=fabs(Cross(b-a,c-a));
	if(dcmp(t4-t3-t2-t1)==0)return true;
	return false;
}
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     int N,M,K;
	 while(cin>>N>>M>>K){
		 memset(head,-1,sizeof(head));tol=0;
		 tot=0;
		 for(int i=1;i<=N;i++)cin>>p1[i].x>>p1[i].y;
		 for(int i=1;i<=N;i++)cin>>dd[i],dd[i]--;
		 for(int i=1;i<=M;i++)cin>>p2[i].x>>p2[i].y;
		 for(int i=1;i<=M;i++)
			 for(int j=i+1;j<=M;j++)
				 for(int k=j+1;k<=M;k++)
					 id[i][j][k]=++tot;
	//	 cout<<"tot="<<tot<<endl;
		 memset(state,0,sizeof(state));
		 for(int i=1;i<=M;i++)
			 for(int j=i+1;j<=M;j++)
				 for(int k=j+1;k<=M;k++)
					 for(int a=1;a<=N;a++)
						 if(check(p2[i],p2[j],p2[k],p1[a]))state[id[i][j][k]]|=(1<<dd[a]);
		 //cout<<"state: ";for(int i=1;i<=tot;i++)cout<<state[i]<<" ";cout<<endl;
		 for(int i=1;i<=M;i++)
			 for(int j=i+1;j<=M;j++)
				 for(int k=j+1;k<=M;k++){
					 double val=dist(p2[i],p2[j])+dist(p2[i],p2[k])+dist(p2[j],p2[k]);
					 addedge(0,id[i][j][k],0);
					 A[id[i][j][k]]=val;
				 }
		 for(int i=1;i<=M;i++)
			 for(int j=i+1;j<=M;j++)
				 for(int k=j+1;k<=M;k++)
					 for(int t=1;t<=M;t++){
						 if(t==i||t==j||t==k)continue;
						 int s1=id[i][j][k],s2;
						 double t1,t2;
						 t1=Cross(p2[j]-p2[i],p2[k]-p2[i]);t2=Cross(p2[j]-p2[i],p2[t]-p2[i]);//i,j共边。
						 if(dcmp(t1)*dcmp(t2)<0)addedge(s1,getid(i,j,t),-2*dist(p2[i],p2[j]));

						 t1=Cross(p2[k]-p2[i],p2[t]-p2[i]);t2=Cross(p2[k]-p2[i],p2[j]-p2[i]);//i,k共边
						 if(dcmp(t1)*dcmp(t2)<0)addedge(s1,getid(i,k,t),-2*dist(p2[i],p2[k]));

						 t1=Cross(p2[k]-p2[j],p2[t]-p2[j]);t2=Cross(p2[k]-p2[j],p2[i]-p2[j]);//j,k共边
						 if(dcmp(t1)*dcmp(t2)<0)addedge(s1,getid(j,k,t),-2*dist(p2[j],p2[k]));
					 }
		 //cout<<"edge: "; for(int i=0;i<tol;i++)cout<<edge[i].val<<endl;
		 for(int i=0;i<=tot;i++)
			 for(int j=0;j<(1<<K);j++)
				 dp[i][j]=INF;
		
		 if(ans<INF)printf("%.12lf\n",ans);
		 else puts("Impossible");
	 }
	 //Point a,b,c,d;while(cin>>a.x>>a.y>>b.x>>b.y>>c.x>>c.y>>d.x>>d.y)cout<<check(a,b,c,d)<<endl;
     return 0;
}