Codeforces 366D 贪心+并查集

最近忙的要死,做作业效率也很低。今天抽了一节水课写了这道上次遗留的题目,不得不说自己实力退步得很厉害,这么简单的题目没有写出来,看来寒假要好好学一下。

回到这道题目,这是一道并查集的题目。

题目大意是:在一个图上有1-n个点,某些点之间连着一些边,每条边上能通过一些数字,有2个信息lr,代表这条边能通过数字[l,r],题目问你从点1走到点n能顺利通过的数字个数,如果没有数字能从1走到n,则输出Nice work, Dima!

题目链接:http://codeforces.com/problemset/problem/366/D

题解:首先我们需要明确如果存在数字能从1走到n,则这些数字必然是连续的。既然输出的数字是连续的,则这些能通过的数字的起始端和结束端必然来自于某些边(某一条或某两条边)。因此我们可以遍历每一条边,假使以第i条边为起始端以第j条边为终端。这时我们又发现了新的问题,如何确定(i,j)这样的组合就是我们想要的答案呢?这时可以用并查集来解决问题,对于每次的以i为起始端的情况,我们将father数组重置,对终端进行扫描。每扫描一条边,就将这条边所连接的2个点连起来,这样我们就在扫描一条新的边的时候能够知道扫描完这条边点1和点n是否已经相连,如果相连,那么这条边就可能是答案所需要的边。但是我们又发现了一个问题:从点1通向点n的路径可能不止一条,如何确定这条边就是终端边呢?这时就需要用到贪心思想了,我们可以把数字的结尾(即r数组)从大到小排序,那么使得点1和点n相连的第一条边就是所要的答案。至此这个问题完全解决!

#include<stdio.h>
#include<stdlib.h>
typedef struct{
	int a,b,l,r;
}In;
In a[3001];
int cmp(const void *a,const void *b){
	return -((*(In*)a).r-(*(In*)b).r);
}
int fa[1001];
int find(int x){
	return fa[x]==x?x:find(fa[x]);
}
int max(int x,int y){
	if (x>y) return x;
	else return y;
}
int main(void){
	int i,j,n,m,ans=0;
	scanf("%d%d",&n,&m);
	for (i=0;i<m;i++) scanf("%d%d%d%d",&a[i].a,&a[i].b,&a[i].l,&a[i].r);
	qsort(a,m,sizeof(a[0]),cmp);
	for (i=0;i<m;i++){
		for (j=1;j<=n;j++) fa[j]=j;
		for (j=0;j<m;j++)
		if (a[j].l<=a[i].l){
			int x=find(a[j].a),y=find(a[j].b);
			if (x!=y) fa[y]=x;
			if (find(1)==find(n)){ans=max(ans,a[j].r-a[i].l+1);break;}
		}
	}
	if (ans) printf("%d\n",ans);
	else printf("Nice work, Dima!\n");
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值