八中生成树2 入门OJ Probloem1639 题解

好了,不废话,先看题:
八中里面有N个建设物,M条边。
对于这种要建最小生成树的问题,你应该很熟练了。
现在老大决定降低某条边的费用,然后这条边必须要被选中,因为这条路他每天都要走,自然…
问选了这条边后是否可以得到一个比从前总开支相等或更小的方案。
Input
第一行三个整数N,M,Q(1<=N<=1000,N-1<=M<=100000
接下来M行,每行三个整数(X,Y,Z)描述一条可以建造的路。 0<=Z<=10000
最后Q行,每行两个整数i,x(1<=i<=M,0<=x)描述一个修改计划,
即要你判断如果 将第i条公路的修建费用降低为x元后,是否可以得到一个比从前总开支相等或更小的方案
Output
按顺序输出Q行,每行输出"Yes"或"No",Yes表示可以建造,No表示不可能
Sample Input
3 4 3
1 2 10
1 3 6
2 3 4
1 3 7
4 6
1 7
1 5
Sample Output
Yes
No
Yes
Sol
这个题的话我们使用prim最小生成树算法强行把它过掉,在作prim生成树时我们再进行一些小处理:因为这个题呢它其实是让我们把任意两点间的最大边算出来,如果最大边的value还要比它给的值还小的话那么就肯定不能选了,所以我们在算prim生成树时我们还要再开一个记录最小生成树上的前驱节点的数组pre,然后求两点间的最大边我打出来吧:

for(int i=1;i<=n;i++)
{
     if(vis[i])
     {
          mx[pos][[i]=mx[i][pos]=max(mx[j][pre[pos]],g[pos][pre[pos]]);
     }
}

mx数组是记录最大value的数组,pos就是所谓的中转点,g数组就是读入时存储两点间距离的数组。
好了,贴code(p.s:本code未经测验但本蒟蒻看不出毛病来,还望各位神犇指出。)

#include<cstdio>
#include<iostream>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1005;
int g[maxn][maxn],low[maxn],pre[maxn],mx[maxn][maxn],n,m,q,tot=0;
bool used[maxn];
struct node
{
	int x,y;
}e[maxn*100];
void add(int a,int b)//存边
{
	e[++tot].x=a;
	e[tot].y=b;
}
void mst_prim()//prim
{
	int pos=1;
	memset(low,127,sizeof(low));//初始化
	memset(used,0,sizeof(used));
	pre[pos]=1,low[pos]=0;
	for(int i=1;i<=n;i++)//prim
	{
		int minl=INF;
		for(int j=1;j<=n;j++)
		{
			if(!used[j]&&minl>low[j])
			{
				minl=low[j];
				pos=j;
			}
		}
		for(int j=1;j<=n;j++)//算最大边距
		{
			if(used[j])
			{
				mx[pos][j]=max(mx[j][pre[pos]],g[pos][pre[pos]]);
				mx[j][pos]=mx[pos][j];
			}
		}
		used[pos]=true;
		for(int ii=1;ii<=n;ii++)
		    if(!used[ii]&&low[ii]>g[pos][ii])//prim最小生成树核心
		    {
		    	low[ii]=g[pos][ii];
		    	pre[ii]=pos;//pre数组记录最小生成树中转点
			}
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&q);
	memset(g,127,sizeof(g));//初始化
	memset(mx,0,sizeof(mx));
	for(int i=1;i<=n;i++)g[i][i]=0;
	for(int i=1;i<=m;i++)
	{
		int a,b,va;
		scanf("%d%d%d",&a,&b,&va);
		add(a,b);//只要存一次
		g[a][b]=g[b][a]=min(g[a][b],va);
	}
	mst_prim();
	for(int i=1;i<=q;i++)
	{
		int aska,askv;
		scanf("%d%d",&aska,&askv);
		if(mx[e[aska].x][e[aska].y]<askv)//如果没有一条边能被添加的边给踢掉的话
		  printf("No\n");
		else
		  printf("Yes\n");
	}
	return 0;
}

好了,本蒟蒻能如此厚颜无耻地将如此之丑的代码贴上来也是深表歉意,还望各位神犇指出其中的不足,在下方评论区,如果没问题的话还望各位神犇巨佬笑纳,本蒟蒻告退了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值