码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2595 Wc2008 游览计划 斯坦纳树

时间:2015-01-08 13:30:32      阅读:157      评论:0      收藏:0      [点我收藏+]

标签:bzoj   bzoj2595   斯坦纳树   

题目大意:给定一个矩阵,有一些关键点,每个格子有权值,选择一些格子使所有关键点连通,求最小权值和

传说中的斯坦纳树- - 感觉不是很难理解的样子

枚举连通的状态,对于每个状态先对每个位置枚举子集进行合并,然后对这个状态的分层图进行SPFA

看了几分代码还是ZKY写的比较简洁- -

此外就是终于能通过操作符重载访问结构体里的三维数组了- - 我真是太丧病了233

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 15
#define INF 0x3f3f3f3f
using namespace std;
struct abcd{
	int x,y,sta;
	abcd() {}
	abcd(int _,int __,int ___):
		x(_),y(__),sta(___) {}
	bool operator ! () const
	{
		return x==0 && y==0 && sta==0 ;
	}
}q[65540];
template<typename T>class Reader{
private:
	struct Subreader{
		T memory[M][1<<10];
		T* operator [] (int x)
		{
			return memory[x];
		}
	}memory[M];
public:
	T& operator [] (const abcd &x)
	{
		return memory[x.x][x.y][x.sta];
	}
	Subreader& operator [] (int x)
	{
		return memory[x];
	}
};
int m,n,cnt;
int map[M][M];
bool mark[M][M];
Reader<int> f;
Reader<bool> v;
Reader<abcd> from;
unsigned short r,h;
void SPFA()
{
	static const int dx[]={1,-1,0,0};
	static const int dy[]={0,0,1,-1};
	int i;
	while(r!=h)
	{
		abcd x=q[++h];v[x]=0;
		for(i=0;i<4;i++)
		{
			abcd y(x.x+dx[i],x.y+dy[i],x.sta);
			if(y.x<=0||y.x>m||y.y<=0||y.y>n)
				continue;
			if(f[y]>f[x]+map[y.x][y.y])
			{
				f[y]=f[x]+map[y.x][y.y];
				from[y]=x;
				if(!v[y])
					v[y]=1,q[++r]=y;
			}
		}
	}
}
void Steiner_Tree()
{
	int i,j,k,sta;
	for(sta=1;sta<1<<cnt;sta++)
	{
		for(i=1;i<=m;i++)
			for(j=1;j<=n;j++)
			{
				for(k=sta&sta-1;k;k=sta&k-1)
					if(f[i][j][sta]>f[i][j][k]+f[i][j][sta-k]-map[i][j])
					{
						f[i][j][sta]=f[i][j][k]+f[i][j][sta-k]-map[i][j];
						from[i][j][sta]=abcd(i,j,k);
					}
				if(f[i][j][sta]!=INF)
					q[++r]=abcd(i,j,sta),v[i][j][sta]=1;
			}
		SPFA();
	}
}
void DFS(abcd x)
{
	if(!from[x]) return ;
	mark[x.x][x.y]=1;
	abcd temp=from[x];
	DFS(temp);
	if( x.x==temp.x && x.y==temp.y )
		DFS(abcd(temp.x,temp.y,x.sta-temp.sta) );
}
int main()
{
	int i,j;
	cin>>m>>n;
	memset(&f,0x3f,sizeof f);
	for(i=1;i<=m;i++)
		for(j=1;j<=n;j++)
		{
			scanf("%d",&map[i][j]);
			if(!map[i][j])
				f[i][j][1<<cnt++]=0;
		}
	Steiner_Tree();
	try{
		for(i=1;i<=m;i++)
			for(j=1;j<=n;j++)
				if(!map[i][j])
					throw(true);
	}catch(bool) {}
	abcd temp(i,j,(1<<cnt)-1);
	cout<<f[temp]<<endl;
	DFS(temp);
	for(i=1;i<=m;i++,puts("") )
		for(j=1;j<=n;j++)
		{
			if(!map[i][j])
				putchar('x');
			else if(mark[i][j])
				putchar('o');
			else
				putchar('_');
		}
	return 0;
}


BZOJ 2595 Wc2008 游览计划 斯坦纳树

标签:bzoj   bzoj2595   斯坦纳树   

原文地址:http://blog.csdn.net/popoqqq/article/details/42521035

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!