• [bzoj2595][WC2008]游览计划/[bzoj5180][Baltic2016]Cities_斯坦纳树


    游览计划 bzoj-2595 wc-2008

    题目大意题目链接题目连接

    注释:略。


    想法:裸题求斯坦纳树。

    斯坦纳树有两种转移方式,设$f[s][i]$表示联通状态为$s$,以$i$为根的最小代价。

    第一个转移就是$f[s][i]=f[t][i]+f[s-t][i]$。这个显然但是是针对边权的,这个题我们需要减掉多算的点权更新答案。

    第二个转移是相同的$s$,即$f[s][i]=f[s][j]+E[i][j]$。

    发现很像三角形不等式,用$spfa$转移即可。

    代码2595

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #define inf 1e9
    #define N 11 
    #define M 1050 
    using namespace std;
    char *p1,*p2,buf[100000];
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int rd() {int x=0,f=1; char c=nc(); while(c<48) {if(c=='-') f=-1; c=nc();} while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;}
    struct Node {int x,y,S;}pre[N][N][M];
    struct par {int x,y;};
    int a[N][N],f[N][N][M];
    int n,m,tot=0;
    int dic_x[]={0,0,1,-1};
    int dic_y[]={1,-1,0,0};
    bool vis[N][N];
    queue<par>q;
    void spfa(int cur)
    {
    	while(!q.empty())
    	{
    		par p=q.front(); q.pop();
    		vis[p.x][p.y]=false;
    		for(int k=0;k<4;k++)
    		{
    			int wx=p.x+dic_x[k],wy=p.y+dic_y[k];
    			if(wx<1||wx>n||wy<1||wy>m) continue;
    			if(f[wx][wy][cur]>f[p.x][p.y][cur]+a[wx][wy])
    			{
    				f[wx][wy][cur]=f[p.x][p.y][cur]+a[wx][wy];
    				pre[wx][wy][cur]=(Node){p.x,p.y,cur};
    				if(!vis[wx][wy]) vis[wx][wy]=true,q.push((par){wx,wy});
    			}
    		}
    	}
    }
    void dfs(int x,int y,int now)
    {
    	// printf("%d %d %d
    ",x,y,now);
    	vis[x][y]=1;
    	// printf("%d %d %d
    ",x,y,now);
    	Node tmp=pre[x][y][now];
    	// printf("%d %d %d
    ",x,y,now);
    	if(!tmp.x&&!tmp.y) return;
    	// printf("%d %d %d
    ",x,y,now);
    	dfs(tmp.x,tmp.y,tmp.S);
    	// printf("%d %d %d
    ",x,y,now);
    	if(tmp.x==x&&tmp.y==y) dfs(tmp.x,tmp.y,now-tmp.S);
    	// printf("%d %d %d
    ",x,y,now);
    }
    int main()
    {
    	n=rd(),m=rd();
    	memset(f,0x3f,sizeof f);
    	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    	{
    		a[i][j]=rd();
    		if(!a[i][j]) f[i][j][1<<tot]=0,tot++;
    	}
    	// for(int i=1;i<=n;i++)
    	// {
    	// 	for(int j=1;j<=m;j++) printf("%d ",a[i][j]);
    	// 	puts("");
    	// }
    	// cout << tot << endl ;
    	int all=(1<<tot)-1;
    	for(int sta=0;sta<=all;sta++)
    	{
    		for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    		{
    			for(int s=sta;s;s=(s-1)&sta)
    			{
    				if(f[i][j][s]+f[i][j][sta-s]-a[i][j]<f[i][j][sta])
    				{
    					f[i][j][sta]=f[i][j][s]+f[i][j][sta-s]-a[i][j];
    					pre[i][j][sta]=(Node){i,j,s};
    				}
    			}
    			if(f[i][j][sta]<inf) q.push((par){i,j}),vis[i][j]=true;
    			// printf("%d
    ",f[i][j][sta]);
    		}
    		spfa(sta);
    	}
    	int ansx,ansy; bool flag=false;
    	for(int i=1;i<=n&&!flag;i++) for(int j=1;j<=m;j++) if(!a[i][j]) {ansx=i,ansy=j,flag=true; break;}
    	cout << f[ansx][ansy][all] << endl ;
    	memset(vis,false,sizeof vis);
    	dfs(ansx,ansy,all);
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=m;j++)
    		{
    			if(!a[i][j]) putchar('x');
    			else if(vis[i][j]) putchar('o');
    			else putchar('_');
    		}
    		puts("");
    	}
    	return 0;
    }
    

    代码5180:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #define N 100010 
    #define M 200010 
    using namespace std; typedef long long ll;
    priority_queue<pair<ll,int> >q;
    int head[N],to[M<<1],nxt[M<<1],tot; ll val[M<<1];
    ll f[50][N];
    bool vis[50][N];
    char *p1,*p2,buf[100000];
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int rd() {int x=0,f=1; char c=nc(); while(c<48) {if(c=='-') f=-1; c=nc();} while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;}
    inline void add(int x,int y,ll z) {to[++tot]=y; val[tot]=z; nxt[tot]=head[x]; head[x]=tot;}
    int main()
    {
    	memset(f,0x3f,sizeof f);
    	int n=rd(),k=rd(),m=rd();
    	for(int i=1;i<=k;i++) {int x=rd(); f[1<<(i-1)][x]=0;}
    	for(int i=1;i<=m;i++) {int x=rd(),y=rd(); ll z=rd(); add(x,y,z),add(y,x,z);}
    	int all=(1<<k)-1;
    	for(int i=1;i<=all;i++)
    	{
    		for(int j=i;j;j=(j-1)&i)
    		{
    			for(int l=1;l<=n;l++)
    			{
    				f[i][l]=min(f[i][l],f[j][l]+f[i-j][l]);
    			}
    		}
    		for(int j=1;j<=n;j++) q.push(make_pair(-f[i][j],j));
    		while(!q.empty())
    		{
    			int x=q.top().second; q.pop();
    			if(vis[i][x]) continue;
    			vis[i][x]=true;
    			for(int j=head[x];j;j=nxt[j]) if(f[i][to[j]]>f[i][x]+val[j])
    			{
    				f[i][to[j]]=f[i][x]+val[j];
    				q.push(make_pair(-f[i][to[j]],to[j]));
    			}
    		}
    	}
    	ll ans=0x3f3f3f3f3f3f3f3f;
    	for(int i=1;i<=n;i++) ans=min(ans,f[all][i]);
    	cout << ans << endl ;
    	return 0;
    }
    

    小结:斯坦纳树类似组合最优化问题,想法非常优秀。

  • 相关阅读:
    DetailsView应用之雕虫小技
    Javascript 调用C# 代码并传递参数的两种方法
    一键还原后,重装一遍 bartender7.75软件, 添加空白标签的时候提示 无法找到字体,无法在没文字情况下运行 求电脑帝解释
    JS处理Enter键触发执行的操作
    SoundManager 2 实现web页面中嵌入声音播放
    用Nexus搭建Maven远程仓库[私服]
    AmCharts一款统计图表及股票图表的插件
    HTML5添加网页音效
    Jquerymenuaim流畅的菜单滑动体验
    UML之JUDE{Astah}使用介绍
  • 原文地址:https://www.cnblogs.com/ShuraK/p/10534880.html
Copyright © 2020-2023  润新知