BZOJ 1097 [POI2007]旅游景点atr dijikstra+状压DP

题意:链接

方法:最短路预处理+状压DP

解析:

看到k=20就想要压一压。

(这种病怎么治!

然后想后来的q个限制。

如果一个点可以被经过的话,那么它的前置点必须都走过。

所以我们要对每个数搞一个压前置点的二进制数。

然后最短路预处理出那k个点以及1号点到任意点的最短路。

状态转移即可。

转移因为枚举不适合,无法做,所以直接上个记忆化就好了。

这题卡常数真的好么 = =

代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 20010
#define M 200100
#define INF 0x3f3f3f3f
using namespace std;
int head[N];
int cnt;
int v[N];
int n,m,k;
int dis[22][1<<20];
int dp[22][1<<20];
int limit[N];
struct node
{
    int from,to,val,next;
}edge[M<<1];
void init()
{
    memset(dp,-1,sizeof(dp));
    memset(dis,0x3f,sizeof(dis));
    memset(head,-1,sizeof(head));
    cnt=1;
}
void edgeadd(int from,int to,int val)
{
    edge[cnt].from=from,edge[cnt].to=to,edge[cnt].val=val;
    edge[cnt].next=head[from],head[from]=cnt++;
}
struct element
{
    int no,val;
};
bool operator < (element a,element b)
{
    if(a.val==b.val)return a.no<b.no;
    return a.val>b.val;
}
void dijikstra(int s)
{
    memset(v,0,sizeof(v));
    priority_queue<element>q;
    element fir;
    fir.no=s,fir.val=0;
    q.push(fir);
    dis[s][s]=0;
    while(!q.empty())
    {
        element u=q.top();
        q.pop();
        if(v[u.no])continue;
        v[u.no]=1;
        for(int i=head[u.no];i!=-1;i=edge[i].next)
        {
            int to=edge[i].to;
            if(u.val+edge[i].val<dis[s][to])
            {
                dis[s][to]=u.val+edge[i].val;
                if(!v[to])
                {
                    element tmp;
                    tmp.no=to,tmp.val=dis[s][to];
                    q.push(tmp);
                }
            }
        }
    }
    dis[s][k+2]=dis[s][n];
}
int dfs(int now,int status)
{
    if(dp[now][status]>=0)return dp[now][status];
    if(status==((1<<k)-1))return dis[now][k+2];
    dp[now][status]=INF;
    for(int i=2;i<=k+1;i++)
    {
        if((status&limit[i])==limit[i])
        {
            dp[now][status]=min(dp[now][status],dis[now][i]+dfs(i,status|(1<<(i-2))));
        }
    }
    return dp[now][status];
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    init();
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        edgeadd(x,y,z);
        edgeadd(y,x,z);
    }
    for(int i=1;i<=k+1;i++)
    {
        dijikstra(i);
    }
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        limit[y]|=(1<<(x-2));
    }
    printf("%d\n",dfs(1,0));
}

你可能感兴趣的:(dp,poi)