• [POI2007]旅游景点atr BZOJ1097


    分析:

    我们可以考虑,因为我们必须经过这些节点,那么我们可以将它状压,并且我们因为可以重复走,只是要求停顿前后,不要求遍历前后,那么我们之间存一下点与点之间的最短路,之后每次转移一下就可以了。

    f[i][S]表示在i节点,状态为S,转移:f[i][S]=max{f[j][S^(1<<i-1)]+dis[i][j]};前后的话,判断一下就可以了,P.S.BZOJ卡时限,**洛谷卡空间

    附上代码:

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    #include <iostream>
    using namespace std;
    #define N 20005
    #define M 1<<20
    struct node
    {
    	int to,next,val;
    }e[N*20];
    int head[N],cnt,f[(M)+10][21],map[21][21],dis[N],vis[N],g[N],cur[21],n,m,k;
    priority_queue <pair<int ,int > >q;
    void add(int x,int y,int z)
    {
    	e[cnt].to=y;
    	e[cnt].next=head[x];
    	e[cnt].val=z;
    	head[x]=cnt++;
    }
    void Dijkstra(int S)
    {
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	while(!q.empty())q.pop();
    	q.push(make_pair(0,S));dis[S]=0;
    	int num=0;
    	while(!q.empty())
    	{
    		if(num==n)break;
    		int x=q.top().second;q.pop();
    		if(vis[x])continue;
    		vis[x]=1;
    		num++;
    		for(int i=head[x];i!=-1;i=e[i].next)
    		{
    			int to1=e[i].to;
    			if(dis[to1]>dis[x]+e[i].val)
    			{
    				dis[to1]=dis[x]+e[i].val;
    				q.push(make_pair(-dis[to1],to1));
    			}
    		}
    	}
    	for(int i=1;i<=k;i++)map[S-1][i]=dis[i+1];
    	if(!cur[S-1])f[1<<(S-2)][S-1]=dis[1];
    	g[S-1]=dis[n];
    }
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d%d",&n,&m,&k);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		add(x,y,z);add(y,x,z);
    	}
    	if(!k)
    	{
    		Dijkstra(1);
    		printf("%d
    ",dis[n]);
    		return 0;
    	}
    	int Q;
    	scanf("%d",&Q);
    	for(int i=1;i<=Q;i++)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		cur[y-1]|=(1<<(x-2));
    	}
    	memset(f,0x3f,sizeof(f));
    	for(int i=2;i<=k+1;i++)Dijkstra(i);
    	for(int S=1;S<1<<k;S++)
    	{
    		for(int i=1;i<=k;i++)
    		{
    			if(S&(1<<(i-1)))
    			{
    				for(int j=1;j<=k;j++)
    				{
    					if(!(S&(1<<(j-1)))&&(S&cur[j])==cur[j])
    					{
    						f[S|(1<<(j-1))][j]=min(f[S|(1<<(j-1))][j],f[S][i]+map[i][j]);
    					}
    				}
    			}
    		}
    	}
    	int ans=1<<30;
    	for(int i=1;i<=k;i++)
    	{
    		ans=min(ans,f[(1<<k)-1][i]+g[i]);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    Ubuntu12.04安装svn1.8
    [NOIP模拟测试3] 建造游乐园 题解(欧拉图性质)
    图论模板
    [bzoj3073] Journeys 题解(线段树优化建图)
    [bzoj3033]太鼓达人 题解(搜索)
    [NOIP2016]天天爱跑步 题解(树上差分) (码长短跑的快)
    [HNOI2015]菜肴制作 题解(贪心+拓扑)
    [SDOI2015]排序 题解 (搜索)
    [CQOI2011]放棋子 题解(dp+组合数学)
    [ZJOI2011]看电影(组合数学/打表+高精)
  • 原文地址:https://www.cnblogs.com/Winniechen/p/9097020.html
Copyright © 2020-2023  润新知