[BZOJ1097][POI2007]旅游景点atr(状压dp)

来源:互联网 发布:app开发编程工具哪个好 编辑:程序博客网 时间:2024/05/17 08:46

题目描述

传送门

题解

这道题的题目描述比较奇怪,而且觉得A掉了之后写的还有小问题= =
不过最大的收获是pre数组的使用:判断之前要经过哪些点。

代码

#include<iostream>#include<cstring>#include<cstdio>#include<queue>using namespace std;const int INF=1e9;const int max_n=2e4+5;const int max_m=2e5+5;const int max_e=max_m*2;const int N=20;int n,m,k,tot,head,tail,ans=INF;int cnt,point[max_n],next[max_e],v[max_e],c[max_e];int pre[max_n],dis[N+5][N+5],f[1<<N][N+5],d[max_n],len[max_n];bool vis[max_n];int q[max_m];inline void add(int x,int y,int z){++cnt,next[cnt]=point[x],point[x]=cnt,v[cnt]=y,c[cnt]=z;}inline void spfa(int s){    memset(q,0,sizeof(q));    head=tail=0; q[++tail]=s;    memset(vis,0,sizeof(vis)); memset(d,0x7f,sizeof(d)); d[s]=0;    while (head!=tail){        int now=q[++head];         vis[now]=false;        for (int i=point[now];i;i=next[i])          if (d[v[i]]>d[now]+c[i]){            d[v[i]]=d[now]+c[i];            if (!vis[v[i]]) vis[v[i]]=true,q[++tail]=v[i];          }    }    for (int i=1;i<=k+1;++i)      dis[s][i]=d[i];    len[s]=d[n];}int main(){    scanf("%d%d%d",&n,&m,&k);    int x,y,z;    for (int i=1;i<=m;++i)       scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);    scanf("%d",&m);    for (int i=1;i<=m;++i)       scanf("%d%d",&x,&y),pre[y]|=1<<(x-2);    for (int i=1;i<=k+1;++i)      spfa(i);    tot=(1<<k)-1;    memset(f,-1,sizeof(f));    f[0][1]=0;    for (int p=0;p<=tot;p++)      for (int i=1;i<=k+1;i++)        if (f[p][i]!=-1)          for (int j=2;j<=k+1;j++){             int nxt=p|(1<<(j-2));             if ((p&pre[j])==pre[j])              if (f[nxt][j]==-1||f[nxt][j]>f[p][i]+dis[i][j])               f[nxt][j]=f[p][i]+dis[i][j];          }    for (int i=1;i<=k+1;++i)      if (f[tot][i]!=-1)        ans=min(ans,f[tot][i]+len[i]);    printf("%d\n",ans);}
0 0
原创粉丝点击