题目
源地址:
http://codeforces.com/problemset/problem/8/C
理解
群里面讨论时,萌神说是一个状态压缩DP,然后我就主动放弃了这道题= =。 实际上,如果用枚举的方法来更新DP,肯定会超时的,有一个小小的技巧在于,小女孩拿东西是没有顺序的。然后在每一次拿东西的时候,都需要更新出两个状态,一种是只拿一个,另一种是拿两个。
代码
#define MAXN 1<<24
int dp[MAXN],pre[MAXN],gra[26][26],x[26],y[26],ans[60];
int n;
int dis(int i, int j)
{
return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
}
void init()
{
int x0,y0;
scanf("%d%d%d", &x0,&y0,&n);
for(int i=0;i<n;i++) scanf("%d%d", &x[i],&y[i]);
x[n]=x0,y[n]=y0;
for(int i=0;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
gra[i][j]=gra[j][i]=dis(i,j);
}
}
memset(dp, -1, sizeof(dp));
dp[0]=0;
}
int main(int argc, char const *argv[])
{
init();
for(int i=0;i<1<<n;i++)
{
if(dp[i]!=-1)
{
for(int j=0;j<n;j++)
{
if(!((1<<j)&i))
{
int t=i|(1<<j),tem=dp[i]+2*gra[j][n];
if(dp[t]==-1||dp[t]>tem)
{
dp[t]=tem;
pre[t]=i;
}
for(int k=0;k<n;k++)
{
if(!(t&(1<<k)))
{
int t2=t|(1<<k),tem=dp[i]+gra[n][j]+gra[j][k]+gra[k][n];
if(dp[t2]==-1||dp[t2]>tem)
{
dp[t2]=tem;
pre[t2]=i;
}
}
}
break;
}
}
}
}
int x=(1<<n)-1,pr,tem,a,b,cnt=0;
printf("%d\n", dp[x]);
while(x)
{
pr=pre[x];
tem=pr^x;
a=b=0;
for(int i=0;i<n;i++)
{
if((1<<i)&tem)
{
b=a;
a=i+1;
}
}
ans[cnt++]=0;
ans[cnt++]=a;
if(b)
{
ans[cnt++]=b;
}
x=pr;
}
ans[cnt++]=0;
for(int i=cnt-1;i>=0;i--)
{
printf("%d ",ans[i]);
}
printf("\n");
return 0;
}
更新日志
- 2014年11月19日 看题解AC,但是还没有理解。
- 2014年11月19日 在妹纸的督促下,完成了。