您的位置:首页 > 其它

HDU 4640 状态压缩DP 未写完

2013-08-03 21:38 288 查看
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4640

解题思路:

首先用一个简单的2^n*n的dp可以求出一个人访问一个给定状态的最小花费,因为这i个人是等价的,所以用dp[i][mask]表示i个人跑完mask这个状态的最小花费,所以首先枚举集合mask,对于dp[i][mask],枚举mask的子集v,dp[i][mask]可以由dp[1][v],dp[i-1][mask^v]转移过来,注意这里用来合并的集合是不能有重复的,这个类似背包……这样就可以算出对于每个状态三个人访问完的最小花费,之后对于给定的需要访问的状态,枚举包含这个给定状态的集合更新答案就可以了……注意对于刚开始给定的图是不能floyd的,因为要求任意两个人的路径不能相交……还有就是1这个节点可以每个人经过多次,这里需要特殊处理一下……

以上摘自杭电的解题报告

下面是我还未写完的代码,我还不会做这个题,所以···还得想想····以后会改好的

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
typedef __int64 lld;
#define pb push_back
#define mp make_pair
#define X first
#define Y second
#define maxn 20
struct Edge
{
int v,s,next;
}edge[1000010];
int head[maxn];
int pos;
void insert(int x,int y,int s)
{
edge[pos].v=y;
edge[pos].s=s;
edge[pos].next=head[x];
head[x]=pos++;
}
int dis[1<<16][16];
bool vis[1<<16][16];
pair<int,int>queue[2000010];
int rear,front;
int maxQ=2000010;
int dp[1<<16];
int f[1<<16];
int main()
{
//    freopen("input.txt","r",stdin);
int cas;
scanf("%d",&cas);
for(int cc=1;cc<=cas;cc++)
{
int n,m;
scanf("%d %d",&n,&m);
memset(head,0,sizeof(head));
pos=1;
while(m--)
{
int x,y,s;
scanf("%d %d %d",&x,&y,&s);
insert(x,y,s);
insert(y,x,s);
}
memset(dis,-1,sizeof(dis));
memset(vis,false,sizeof(vis));
rear=front=0;
for(int i=head[1];i;i=edge[i].next)
{
int v=edge[i].v;
v-=2;
if(dis[1<<v][v] == -1 || edge[i].s < dis[1<<v][v])
{
dis[1<<v][v]=edge[i].s;
if(!vis[1<<v][v])
{
vis[1<<v][v]=true;
queue[front++]=mp(1<<v,v);
}
}
}
while(rear != front)
{
int mask=queue[rear].X;
int u=queue[rear].Y;
rear++;
if(rear == maxQ)
rear=0;
vis[mask][u]=false;
for(int i=head[u+2];i;i=edge[i].next)
{
int v=edge[i].v;
if(v == 1)
continue;
v-=2;
int next=mask|(1<<v);
if(dis[next][v] == -1 || dis[mask][u]+edge[i].s < dis[next][v])
{
dis[next][v]=dis[mask][u]+edge[i].s;
if(!vis[next][v])
{
vis[next][v]=true;
queue[front++]=mp(next,v);
if(front == maxQ)
front=0;
}
}
}
}
memset(dp,-1,sizeof(dp));
dp[0]=0;
int T=1<<(n-1);
for(int mask=1;mask<T;mask++)
for(int i=0;i<n-1;i++)
{
if(dis[mask][i] == -1)
continue;
if(dp[mask] == -1 || dis[mask][i] < dp[mask])
dp[mask]=dis[mask][i];
}
for(int mask=0;mask<T;mask++)
f[mask]=dp[mask];
for(int k=0;k<2;k++)
{
for(int u=T-1;u>0;u--)
for(int v1=u;;v1=(v1-1)&u)
{
int v2=u^v1;
if(dp[v1] == -1 || f[v2] == -1)
{
if(v1 == 0)
break;
continue;
}
if(dp[u] == -1 || max(dp[v1],f[v2]) < dp[u])
dp[u]=max(dp[v1],f[v2]);
if(v1 == 0)
break;
}
}
int Q;
scanf("%d",&Q);
int mask=0;
while(Q--)
{
int x;
scanf("%d",&x);
x-=2;
mask|=1<<x;
}
int ans=-1;
for(int u=0;u<T;u++)
if((u&mask) == mask)
{
if(dp[u] == -1)
continue;
if(ans == -1 || dp[u] < ans)
ans=dp[u];
}
printf("Case %d: %d\n",cc,ans);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: