• luogu P4294 [WC2008]游览计划


    LINK:游览计划

    斯坦纳树例题。

    斯坦纳树是这样一类问题:带权无向图上有K个关键点 求出包含这K个点的最小生成树。

    也就是说 求最小生成树 但是 并不是整张图 仅限于K个点。

    可以发现我们利用克鲁斯卡尔或者prim算法 求的都是整张图的最小生成树。

    所以可以发现 这个斯坦纳树问题 其实是一个np困难问题 不存在多项式的时间复杂度。

    可以考虑搜索或者状压了。

    这道题共有100个点 其中有10个关键点 我们首选状压dp.

    有状态 f[i][j][k]表示到了(i,j)这个点了 所经过的点集为k的最小代价。

    可以发现我们的i,j 这个点可以先往左再往右走 什么的所以有一个比较显然的转移。

    f[i][j][k]=min{f[i][j][s]+f[i][j][s^k]-val[i][j]};

    还有一个转移 如果当前点 跑到其他地方了f[x][y][k]=min{f[i][j][k]+val[x][y]};

    两个转移就完了。其中第一个状态转移方程 我们可以直接枚举子集来做。

    第二个考虑跑spfa来进行迭代dp.

    可以发现是可以跑dij 可能dij在稀疏图中并不优秀?我觉着没有spfa快。

    const int MAXN=11;
    int n,m,cnt,l,r;
    int f[MAXN][MAXN][1<<10];
    int a[MAXN][MAXN],vis[MAXN][MAXN];
    pii pre[MAXN][MAXN][1<<10];
    pii q[10010];
    int dx[5]={0,0,0,1,-1};
    int dy[5]={0,1,-1,0,0};
    inline void spfa(int s)
    {
    	while(++l<=r)
    	{
    		pii w=q[l];vis[w.F][w.S]=0;
    		rep(1,4,i)
    		{
    			int xx=w.F+dx[i];
    			int yy=w.S+dy[i];
    			if(xx<1||yy<1||xx>n||yy>m)continue;
    			if(f[xx][yy][s]>f[w.F][w.S][s]+a[xx][yy])
    			{
    				f[xx][yy][s]=f[w.F][w.S][s]+a[xx][yy];
    				pre[xx][yy][s]=w;
    				if(!vis[xx][yy])vis[xx][yy]=1,q[++r]=mk(xx,yy);
    			}
    		}
    	}
    }
    inline void get_path(int x,int y,int s)
    {
    	vis[x][y]=1;
    	pii w=pre[x][y][s];
    	if(!w.F&&!w.S)return;
    	if(!w.F)get_path(x,y,w.S),get_path(x,y,w.S^s);
    	else get_path(w.F,w.S,s);
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	memset(f,0x3f,sizeof(f));
    	get(n);get(m);int s1,s2;
    	rep(1,n,i)rep(1,m,j)
    	{
    		get(a[i][j]);
    		if(!a[i][j])s1=i,s2=j,++cnt,f[i][j][1<<(cnt-1)]=0;
    	}
    	int maxx=(1<<cnt)-1;
    	rep(1,maxx,i)
    	{
    		l=r=0;
    		for(int x=1;x<=n;++x)
    			for(int y=1;y<=m;++y)
    			{
    				for(int s=i;s;s=i&(s-1))
    					if(f[x][y][s]+f[x][y][s^i]-a[x][y]<f[x][y][i])
    						f[x][y][i]=f[x][y][s]+f[x][y][s^i]-a[x][y],pre[x][y][i]=mk(0,s);
    				if(f[x][y][i]<INF)
    				{
    					q[++r]=mk(x,y);
    					vis[x][y]=1;
    				}
    			}
    		spfa(i);
    	}
    	put(f[s1][s2][maxx]);
    	get_path(s1,s2,maxx);
    	rep(1,n,i)
    	{
    		rep(1,m,j)
    		{
    			if(!a[i][j])putchar('x');
    			else putchar(vis[i][j]?'o':'_');
    		}
    		puts("");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java——HashMap
    Java——Collections
    Java——String,StringBuffer,StringBuilder
    OpenModelica读取文件
    Excel 常用设置
    Ubuntu16 源码方式安装postgresql数据库
    Utunbu常见问题
    PostgreSQL 扩展开发基础教程
    《数据挖掘导论》
    高性能MySQL --- 读书笔记(2)
  • 原文地址:https://www.cnblogs.com/chdy/p/12551467.html
Copyright © 2020-2023  润新知