暑假集训之专题----拓扑排序题解

第一单:

Problem A

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 26   Accepted Submission(s) : 5

Problem Description

ACM-DIY is a large QQ group where many excellent acmers get together. It is so harmonious that just like a big family. Every day,many "holy cows" like HH, hh, AC, ZT, lcc, BF, Qinz and so on chat on-line to exchange their ideas. When someone has questions, many warm-hearted cows like Lost will come to help. Then the one being helped will call Lost "master", and Lost will have a nice "prentice". By and by, there are many pairs of "master and prentice". But then problem occurs: there are too many masters and too many prentices, how can we know whether it is legal or not? We all know a master can have many prentices and a prentice may have a lot of masters too, it‘s legal. Nevertheless,some cows are not so honest, they hold illegal relationship. Take HH and 3xian for instant, HH is 3xian‘s master and, at the same time, 3xian is HH‘s master,which is quite illegal! To avoid this,please help us to judge whether their relationship is legal or not. Please note that the "master and prentice" relation is transitive. It means that if A is B‘s master ans B is C‘s master, then A is C‘s master.

Input

The input consists of several test cases. For each case, the first line contains two integers, N (members to be tested) and M (relationships to be tested)(2 <= N, M <= 100). Then M lines follow, each contains a pair of (x, y) which means x is y‘s master and y is x‘s prentice. The input is terminated by N = 0. TO MAKE IT SIMPLE, we give every one a number (0, 1, 2,..., N-1). We use their numbers instead of their names.

Output

For each test case, print in one line the judgement of the messy relationship. If it is legal, output "YES", otherwise "NO".

Sample Input

3 2
0 1
1 2
2 2
0 1
1 0
0 0

Sample Output

YES

NO

裸裸的拓扑排序,只需要判断是否成环即可.......

代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 const int maxn=105;
 5 int map[maxn][maxn];
 6 int indegree[maxn];
 7 int n,m;
 8 int main()
 9 {
10     int x,y;
11     while(scanf("%d%d",&n,&m)!=EOF&&n+m!=0)
12     {
13      memset(map,0,sizeof(map));
14      memset(indegree,0,sizeof(indegree));
15       while(m--)
16       {
17         scanf("%d%d",&x,&y);
18         x++;
19         y++;
20         if(!map[x][y])
21         {
22          map[x][y]=1;
23          indegree[y]++;
24         }
25       }
26       int j;
27       bool flag=1;
28       for(int i=1;i<=n;i++)
29       {
30           for(j=1;j<=n;j++)
31           {
32               if(indegree[j]==0)
33               {
34                 indegree[j]--;
35                 for(int k=1;k<=n;k++)
36                 {
37                   if(map[j][k])
38                     indegree[k]--;
39                 }
40                 break ;
41               }
42           }
43           if(j>n){
44             flag=0;
45             break;
46           }
47       }
48       printf(flag==0?"NO\n":"YES\n");
49     }
50  return 0;
51 }

Problem A

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 25   Accepted Submission(s) : 8

Problem Description

有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

Input

输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。

Output

给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。 其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。

Sample Input

4 3
1 2
2 3
4 3

Sample Output

1 2 4 3

基础题

代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 #define maxn 505
 5 bool map[maxn][maxn];
 6 int indegree[maxn],tp[maxn],n,m;
 7 void tuopu_sort()
 8 {
 9     memset(tp,0,sizeof(tp)); //拓扑排序数组清空
10     int i,j,k=0,ll;
11     for(i=1;i<=n;i++)
12     {
13         for(j=1;j<=n;j++)
14         {
15          /*每次取出入读位0的数*/
16             if(indegree[j]==0)
17             {
18                 indegree[j]=-1;  //让他等于-1;表示舍弃掉这个数
19                 tp[k++]=j;  //放到拓扑序列中
20                 /*进行一次循环,去掉所有这个数指向的数的一个度*/
21                 for(ll=1;ll<=n;ll++)
22                 {
23                     if(map[j][ll])  //j-->LL 表示成为map[j][ll]
24                     {
25                         indegree[ll]--;  //减少一个
26                     }
27                 }
28                 break;  // 终止,然后进行下次的查找
29             }
30         }
31         if(j>n)
32         {
33             //这表示构成了一个环
34             return ;  //之间结束即可,但是在其他的题中,不能这样...
35         }
36     }
37 }
38 int main()
39 {
40     int i=0,fx,ty;//  fx--->from x to y
41     while(scanf("%d%d",&n,&m)!=EOF)
42     {
43         memset(map,0,sizeof(map));
44         memset(indegree,0,sizeof(indegree));
45         for(i=0;i<m;i++)
46         {
47             scanf("%d%d",&fx,&ty);
48             if(!map[fx][ty])      //防止数据重复
49             {
50               map[fx][ty]=true;
51               indegree[ty]++;     //入度加一
52             }
53         }
54         tuopu_sort();
55         for(i=0;i<n-1;i++)
56         {
57             printf("%d ",tp[i]);
58         }
59         printf("%d\n",tp[i]);
60     }
61     return 0;
62 }

Problem B

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 17   Accepted Submission(s) : 1

Problem Description

Dandelion‘s uncle is a boss of a factory. As the spring festival is coming , he wants to distribute rewards to his workers. Now he has a trouble about how to distribute the rewards. The workers will compare their rewards ,and some one may have demands of the distributing of rewards ,just like a‘s reward should more than b‘s.Dandelion‘s unclue wants to fulfill all the demands, of course ,he wants to use the least money.Every work‘s reward will be at least 888 , because it‘s a lucky number.

Input

One line with two integers n and m ,stands for the number of works and the number of demands .(n<=10000,m<=20000) then m lines ,each line contains two integers a and b ,stands for a‘s reward should be more than b‘s.

Output

For every case ,print the least money dandelion ‘s uncle needs to distribute .If it‘s impossible to fulfill all the works‘ demands ,print -1.

Sample Input

2 1
1 2
2 2
1 2
2 1

Sample Output

1777
-1

用邻接表取代邻接矩阵(或者用STL取代之)

代码:

 1  /*@coder 龚细军*/
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<queue>
 6 #include<vector>  //动态的二维数组
 7 #include<iostream>
 8 using namespace std;
 9 const int maxn=10002;
10 int n,m;
11 int cnt[maxn],outd[maxn];
12 vector< vector<int> >map(maxn);
13 void tp_sort(int tol)
14 {
15  int i;
16  queue<int>st;
17  for(i=1;i<=n;i++)
18  {
19   if(!outd[i])
20   {
21    outd[i]--;
22    st.push(i);
23    break;
24   }
25  }
26  //环如何消除
27  while(!st.empty())
28  {
29   int temp=st.front();
30   vector<int>::iterator it;
31   for(it=map[temp].begin();it!=map[temp].end();it++)
32   {
33    outd[*it]--;
34    if(cnt[*it]<=cnt[temp])
35     cnt[*it]=cnt[temp]+1;
36   }
37   st.pop();
38   for(i=1;i<=n;i++)
39   {
40    if(!outd[i])
41    {
42    outd[i]--;
43    st.push(i);
44    break;
45    }
46   }
47  }
48  for(i=1;i<=n;i++)
49  {
50   if(outd[i]!=-1)
51   {
52    puts("-1");
53    return ;
54   }
55  }
56   int ans=0;
57   for(i=1;i<=n;i++)
58   {
59    ans+=cnt[i];
60   }
61   if(ans)
62      printf("%d\n",n*888+ans);
63   else
64    puts("-1");
65 }
66 int main()
67 {
68  int a,b,i;
69  while(scanf("%d%d",&n,&m)!=EOF)
70  {
71   for(i=1;i<=n;i++) map[i].clear();
72   memset(outd,0,sizeof(outd));
73   memset(cnt,0,sizeof(cnt));
74   i=1;
75   while(m--)
76   {
77       scanf("%d%d",&a,&b);
78    map[b].push_back(a);
79    outd[a]++;    /*out++*/
80   }
81   tp_sort(i);
82  }
83  return 0;
84 }

暑假集训之专题----拓扑排序题解

时间: 2024-11-05 19:04:51

暑假集训之专题----拓扑排序题解的相关文章

UVa 10305 - Ordering Tasks 拓扑排序题解

Topological Sort题解.本题是简单的入门题目. Topological Sort的思想很简单,就是按没有入度的点,先输出,然后删除这个点的出度.然后输出下一组没有入度的点. 如何实现也是很简单的: 这里使用邻接表,建图的时候反过来建图,建立一个入度邻接表. 然后使用一个vis数组,记录访问过的节点,也可以根据这个信息知道哪些是已经输出的点,这个时候这些点的入度可以不算为当前入度了. #include <stdio.h> #include <vector> using

[CSP校内集训]pestc(拓扑排序)

题意 给一个边带权的有向图,可以花费边权使得一条边反向:通过翻转边让原图变成一个DAG,要求是所有花费中的最大值最小\(,(n,m\leq 200000)\),保证无重边和自环 解法1 考场上没看出来性质,于是口胡了一个乱搞做法 连好边后直接对原图进行一遍拓扑排序,由于原图不是DAG,所以会有无法入队的环存在:如果当前队列为空而有点没有被遍历到,那么就强行选择一个点将连向它的边翻转: 具体的,我们选择\((max(\) 连向\(i\)的边 \())\)最小的\(i\),由于翻转了连向\(i\)的

acm专题---拓扑排序+优先队列

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1285 Problem Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前.现在请你编程序确定排名. Input 输入有若干组,每组中的第一行为二个数N(1<=N&l

HDU 5638 拓扑排序+优先队列

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5638 题意: 给你一个DAG图,删除k条边,使得能个得到字典序尽可能小的拓扑排序 题解: 把拓扑排序的算法稍微改一下,如果某个顶点的入度小于k也把它加到优先队列里面去. k减小后队列里面会有些点不满足<=k,直接踢出来就好了. 代码: #include<iostream> #include<cstring> #include<cstdio> #include<

暑假集训练习赛题解

比赛链接:http://acm.nyist.net/JudgeOnline/problemset.php?cid=205 对于第一道题 UFS(Union  Find  Set) ,请参见http://blog.csdn.net/u011632342/article/details/37814289,题目大意一样,解法一样,不过后台测试数据还没整太多,数据比较弱... 对于第二道题STR(STRing),本来是想着给大家"送福利"呢,可能由于我的题目表述能力不太好或者样例数据的特殊性或

【基础练习】【拓扑排序】codevs3294 车站分级题解

题目来源:NOIP2013 普及第四题 题目描写叙述 Description 一条单向的铁路线上,依次有编号为1, 2, -, n的n个火车站.每一个火车站都有一个级别,最低为1级.现有若干趟车次在这条线路上行驶.每一趟都满足例如以下要求:假设这趟车次停靠了火车站x.则始发站.终点站之间全部级别大于等于火车站x的都必须停靠. (注意:起始站和终点站自然也算作事先已知须要停靠的网站) 比如,下表是5趟车次的执行情况.当中.前4趟车次均满足要求,而第5趟车次因为停靠了3号火车站(2级)却未停靠途经的

【题解】AT1984 Wide Swap(拓扑排序)

[题解]AT1984 Wide Swap(拓扑排序) 排列问题的一大套路是考虑arc数组(arc[data[t]]=t) 然后题目那个swap的性质,就转换为了对于arc数组相邻的值,若其差大于等于\(k\)则可以交换,否则不能. 考虑arc数组上任意两个数\(x,y\)(假设x的位置<y的位置)能够交换的条件,条件就是在\(x,y\)之间不存在和他们的差小于\(k\)的数.但如果有的话,那么\(x,y\)永远也不能交换了.也就是说,最终答案中,位置为\(x\)的数一定会小于位置\(y\)的数.

寒假集训日志(二)——最小生成树,拓扑排序,欧拉回路,连通路

今天学的内容挺多的. (一)首先说最小生成树,两种算法: 1.Kruskal算法( 将边排序,然后再选,关键在于检查是否连通,使用并查集) 2.Prim算法(使用点集,有点类似与最短路的算法) 第一题是并查集算法的使用: A - The Suspects Time Limit:1000MS     Memory Limit:20000KB     64bit IO Format:%I64d & %I64u Submit Status Description 严重急性呼吸系统综合症( SARS),

20151230训练题解(最短路+拓扑排序)

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=103223#problem/B 这道题用经典的dijsktra算法,大概思路就是用dist[x]存储x到已经确定集合的最短路,n次循环到这个这个最小值,然后更新其他点到新集合的最短路即对应的dist[] 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <al