hdu4281是多旅行商问题,hdu4640是三个旅行商,这不太影响解法,主要差别在于hdu4640要求不仅仅是每个节点访问一次,而且要每个节点只能经过一次,这样求single[state][u]的时候就不能直接枚举下一个点了,而是要根据边枚举,且下一个到达的点必影响state。
hdu4281:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<numeric>
#include<queue>
using namespace std;
const int inf=0x3fffffff;
int path[20][20];
double x[20],y[20];
int n,m,c[20];
int dp1[1<<20];
int state[1<<20],tot;
bool ok[1<<20];
void pre()
{
tot=0;
int i,j,sum;
memset(ok,false,sizeof(ok));
for(i=0;i<(1<<n);++i)
{
sum=0;
for(j=0;j<n;++j)
{
if(i&(1<<j))
{
sum+=c[j];
}
}
if(sum<=m)
{
ok[i]=true;
state[tot++]=i;
}
}
}
int solve1() //checked
{
int i,j;
for(i=0;i<(1<<n);++i)
dp1[i]=inf;
dp1[0]=0;
for(i=1;i<(1<<n);++i)
{
for(j=0;j<tot;++j)
{
if((i|state[j])==i)
{
dp1[i]=min(dp1[i],dp1[i-state[j]]+1);
}
}
}
return dp1[(1<<n)-1]==inf?-1:dp1[(1<<n)-1];
}
int single[1<<20][20],best[1<<20];
int solve2()
{
int i,j,k,u,v;
for(i=0;i<(1<<n);++i)
{
for(j=0;j<n;++j)
single[i][j]=inf;
best[i]=inf;
}
single[1][0]=0;
for(i=1;i<(1<<n);++i)
{
if(ok[i])
{
for(j=0;j<n;++j)
{
if(i&(1<<j))
{
best[i]=min(best[i],single[i][j]+path[j][0]);
for(k=0;k<n;++k)
{
if(ok[i|(1<<k)]&&((i&(1<<k))==0))
{
single[i|(1<<k)][k]=min(single[i|(1<<k)][k],single[i][j]+path[j][k]);
}
}
}
}
}
}
for(i=0;i<(1<<n);++i)
{
for(j=i&(i-1);j;j=((j-1)&i))
{
best[i]=min(best[i],best[j]+best[(i^j)|1]);
if(j==0)
break;
}
}
return best[(1<<n)-1];
}
int main()
{
int i,j,k,ans1,ans2;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=0;i<n;++i)
{
scanf("%lf%lf",&x[i],&y[i]);
}
for(i=0;i<n;++i)
{
scanf("%d",&c[i]);
}
memset(path,0,sizeof(path));
for(i=0;i<n;++i)
{
for(j=i+1;j<n;++j)
{
path[i][j]=path[j][i]=ceil(sqrt(pow(x[i]-x[j],2)+pow(y[i]-y[j],2)));
}
}
for(k=0;k<n;++k)
{
for(i=0;i<n;++i)
{
for(j=0;j<n;++j)
{
path[i][j]=min(path[i][j],path[i][k]+path[k][j]);
}
}
}
pre();
ans1=solve1();
if(ans1==-1)
{
printf("-1 -1\n");
}
else
{
ans2=solve2();
printf("%d %d\n",ans1,ans2);
}
}
return 0;
}
hdu4640:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int inf=0x3fffffff;
const int maxn=20;
int single[1<<maxn][20];
int dp[2][1<<maxn];
struct edge
{
int to,w,next;
}ee[maxn*maxn*2];
int e[maxn],ecnt,n,m;
void addedge(int u,int v,int c)
{
ee[ecnt].to=v;ee[ecnt].w=c;ee[ecnt].next=e[u];e[u]=ecnt++;
ee[ecnt].to=u;ee[ecnt].w=c;ee[ecnt].next=e[v];e[v]=ecnt++;
}
void bfs()
{
int u,msk1,msk2,v,i,j;
for(msk1=0;msk1<(1<<n);++msk1)
{
for(u=0;u<n;++u)
{
single[msk1][u]=inf;
}
}
queue<int> q1,q2;
q1.push(1);q2.push(0);single[1][0]=0;
while(!q1.empty())
{
msk1=q1.front();q1.pop();
u=q2.front();q2.pop();
for(i=e[u];i!=-1;i=ee[i].next)
{
v=ee[i].to;
if(single[msk1|(1<<v)][v]>single[msk1][u]+ee[i].w)
{
single[msk1|(1<<v)][v]=single[msk1][u]+ee[i].w;
q1.push(msk1|(1<<v));q2.push(v);
}
}
}
for(msk1=2;msk1<(1<<n);++msk1)
{
dp[0][msk1>>1]=inf;
for(j=0;j<n;++j)
{
dp[0][msk1>>1]=min(dp[0][msk1>>1],single[msk1|1][j]);
}
}
dp[0][0]=0;
}
int main()
{
int t,cas=0,i,j,u,v,c,ans,tar,k,msk1,msk2;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(e,-1,sizeof(e));ecnt=0;
while(m--)
{
scanf("%d%d%d",&u,&v,&c);
u--;v--;
addedge(u,v,c);
}
tar=0;
scanf("%d",&k);
while(k--)
{
scanf("%d",&u);
u-=2;
tar|=(1<<u);
}
bfs();
n--;
for(msk1=0;msk1<(1<<n);msk1++)
{
dp[1][msk1]=inf;
for(msk2=msk1;;msk2=((msk2-1)&msk1))
{
if(dp[0][msk2]!=inf&&dp[0][msk1^msk2]!=inf)
{
dp[1][msk1]=min(dp[1][msk1],max(dp[0][msk2],dp[0][msk1^msk2]));
}
if(msk2==0)
break;
}
}
ans=inf;
for(msk1=0;msk1<(1<<n);msk1++)
{
if((msk1&tar)==tar)
{
for(msk2=msk1;;msk2=((msk2-1)&msk1))
{
ans=min(ans,max(dp[0][msk2],dp[1][msk2^msk1]));
if(msk2==0)
break;
}
}
}
if(ans==inf)
{
printf("Case %d: -1\n",++cas);
}
else
{
printf("Case %d: %d\n",++cas,ans);
}
}
return 0;
}

被折叠的 条评论
为什么被折叠?



