最近忙的要死,做作业效率也很低。今天抽了一节水课写了这道上次遗留的题目,不得不说自己实力退步得很厉害,这么简单的题目没有写出来,看来寒假要好好学一下。
回到这道题目,这是一道并查集的题目。
题目大意是:在一个图上有1-n个点,某些点之间连着一些边,每条边上能通过一些数字,有2个信息l和r,代表这条边能通过数字[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;
}