【刷题】BZOJ 4349 最小树形图

Description

小C现在正要攻打科学馆腹地------计算机第三机房。而信息组的同学们已经建好了一座座堡垒,准备迎战。小C作为一种高度智慧的可怕生物,早已对同学们的信息了如指掌。

攻打每一个人的堡垒需要一个代价,而且必须攻打若干次才能把镇守之人灭得灰飞烟灭。

当小C在绞尽脑汁想攻打方案时,突然从XXX的堡垒中滚出来一个纸条:一个惊人的秘密被小C发现了:原来各个堡垒之间会相互提供援助,但是当一个堡垒被攻打时,他对所援助的堡垒的援助就会停止,因为他自己已经自身难保了。也就是说,小C只要攻打某个堡垒一次之后,某些堡垒就只需要花更小的代价攻击了。

现在,要你求消灭全机房要用掉代价最小多少。

Input

第一行一个数N,(N<=50),表示机房修建的堡垒数。

接下来N行,每行两个数,第一个实数Ai表示攻打i号堡垒需要的代价Ai(0<Ai<=1000)。第二个数Bi(0<Bi<100)表示i号堡垒需要被攻打Bi次。

接下来一个数k,表示总共有k组依赖关系。

接下来k行每行三个数x,y,z(x,y,为整数,z为实数),表示攻打过一次x号堡垒之后,攻打y号堡垒就只要花z的代价,保证z比y原来的代价小。

不需要攻打的城堡不允许攻打。

Output

一行,一个实数表示消灭全机房要用的最小代价,保留两位小数。

Sample Input

3
10.00 1
1.80 1
2.50 2
2
1 3 2.00
3 2 1.50

Sample Output

15.50

Solution

最小树形图
首先肯定是到达所有需要到达的点一遍,然后每个点都用最小代价攻打
所以按输入将图建出来,每条边的边权就是攻打代价
然后跑最小树形图,最后贪心增加其它代价

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=50+5,MAXM=MAXN*MAXN;
const db inf=100000000000.00;
int n,m,times[MAXN],vis[MAXN],bel[MAXN],snt,s,pre[MAXN],nd,M[MAXN];
db in[MAXN],G[MAXN][MAXN],ans;
struct node{
	int u,v;
	db k;
};
node side[MAXM];
template<typename T> inline void read(T &x)
{
	T data=0,w=1;
	char ch=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
	x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
	if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline db solve(int rt,int n)
{
	db res=0;
	while(true)
	{
		for(register int i=1;i<=n;++i)in[i]=inf;
		for(register int i=1;i<=snt;++i)
			if(side[i].u!=side[i].v&&in[side[i].v]>side[i].k)in[side[i].v]=side[i].k,pre[side[i].v]=side[i].u;
		for(register int i=1;i<=n;++i)
			if(i!=rt&&in[i]==inf)return -1;
		int cnt=0;
		memset(bel,0,sizeof(bel));
		memset(vis,0,sizeof(vis));
		in[rt]=0;
		for(register int i=1,j;i<=n;++i)
		{
			res+=in[i];j=i;
			while(j!=rt&&vis[j]!=i&&!bel[j])vis[j]=i,j=pre[j];
			if(j!=rt&&!bel[j])
			{
				bel[j]=++cnt;
				for(register int k=pre[j];k!=j;k=pre[k])bel[k]=cnt;
			}
		}
		if(!cnt)break;
		for(register int i=1;i<=n;++i)
			if(!bel[i])bel[i]=++cnt;
		for(register int i=1,u,v;i<=snt;++i)
		{
			u=side[i].u,v=side[i].v;
			side[i].u=bel[u];side[i].v=bel[v];
			if(bel[u]^bel[v])side[i].k-=in[v];
		}
		n=cnt;
		rt=bel[rt];
	}
	return res;
}
int main()
{
	read(n);
	s=++nd;
	for(register int i=1;i<=n;++i)
	{
		in[i]=inf;
		db cost;scanf("%lf",&cost);read(times[i]);
		if(times[i])
		{
			M[i]=++nd;
			side[++snt]=(node){s,M[i],cost};
			chkmin(in[i],cost);
		}
	}
	read(m);
	for(register int i=1;i<=m;++i)
	{
		int x,y;read(x);read(y);
		db cost;scanf("%lf",&cost);
		if(M[x]&&M[y])
		{
			side[++snt]=(node){M[x],M[y],cost};
			chkmin(in[y],cost);
		}
	}
	for(register int i=1;i<=n;++i)
		if(times[i]>1)ans+=(times[i]-1)*in[i];
	printf("%.2f\n",ans+solve(s,nd));
	return 0;
}
posted @ 2018-07-09 20:05  HYJ_cnyali  阅读(245)  评论(0编辑  收藏  举报