XMUT 简单图论专场(拓扑排序、最小生成树、贪心)
来源:互联网 发布:淘宝寄澳洲,电话号码 编辑:程序博客网 时间:2024/06/03 05:04
A - 小Y上学记——修学分
Problem Description
小Y终于如愿以偿地通过高考来到了魂牵梦萦的大学校园——ACdream大学。来到校园的第一件事就是选课。
由于每一门课都有1个学分~而且有一些课需要先学完别的课程(例如必须先学会高等数学,才能学会量子力学,必须先学会走,才能学会跑)
ACdream大学需要学生修够若干学分才允许毕业。
请按顺序输出小Y的一种方案(若不止一种答案,请输出字典序最小的一种方案)
Input
多组数据,每组数据首先是两个整数n,m,k,分别表示学科总数,学科之间的关系数,以及毕业所需的最少学分。
(2<=n<=100, 0<=m<=500,1<=k<=n)
接下来是m行,每行是两个整数a,b表示学科a是学科b的前置学科。
Output
对于每组数据,若小Y不存在任何方案选课,请输出-1.
否则在一行输出m个整数,表示小Y按顺序修的学科编号。
Sample Input
2 1 20 12 2 21 00 13 2 11 00 13 0 3
Sample Output
0 1-120 1 2
Hint
对于第一组数据,先修完第0学科,获得1学分,再修以第0学科为前置学科的第1学科,获得1学分,即可满足毕业条件:2学分。
对于第二组数据,由于第0学科的前置学科为第1学科,而第1学科的前置学科为第2学科,因此小Y无论如何也无法满足毕业条件。
对于第三组数据,由于多了第2学科,而且第2学科不需要前置学科,因此只需要修完第2学科即可满足毕业条件了。
对于第四组数据,没有任何的先后限制,因此6种全排列方案均符合题意,字典序最小的方案为0,1,2
这里有一道我做过的类似题目可供参考:http://blog.csdn.net/enjoying_science/article/details/47380099
编程思想:根据题意,可抽象成图的拓扑排序。这里采用map和链式前向星两种方法来实现拓扑排序算法。
AC code1(map方式):
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<queue>#include<math.h>#include<vector>#include<map>#include<set>#include<cmath>#include<string>#include<algorithm>#include<iostream>#define LL long long #define exp 1e-10#define MAXN 1000010using namespace std;const int INF=0x3f3f3f3f;const int N = 100005;const int mod = 1000000007;int ma[555][555];int ind[555];int ans[555];int main(){//freopen("D:\in.txt","r",stdin);int n,m,k,i,j,cnt;while(scanf("%d%d%d",&n,&m,&k)!=EOF){memset(ma,0,sizeof(ma));memset(ind,0,sizeof(ind));for(i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);if(!ma[a][b]){ma[a][b]=1;ind[b]++;}}int node;cnt=0;for(i=0;i<n;i++)//i为成功拓扑排序的点的个数 {for(j=0;j<n;j++)//点的编号是从0开始的 {if(ind[j]==0){node=j;ind[node]--;ans[i]=node;for(int jj=0;jj<n;jj++){if(ma[node][jj]){ind[jj]--;}}break;}}if(j==n)//点的编号是从0开始的,到n-1都遍历完,直接跳出break;}if(i<k)//i为成功拓扑排序的点的个数 {printf("-1\n");}else{printf("%d",ans[0]);for(i=1;i<k;i++){printf(" %d",ans[i]);}printf("\n");}}return 0;}
AC code2(链式前向星):
#include <iostream>#include <stdio.h>#include <string.h>#include <map>#define MAX 505using namespace std;int InD[505];/*InD[i]记录点i的入度*/int First[MAX];/*First[i]头结点的第一条边的编号*/struct edge{ int TO;/*点*/ int Next;/*下一条边的编号*/}ID[3*MAX];int SIGN;void Add_E(int x,int y)/*添加点操作*/{ ID[SIGN].TO=y; InD[y]++; ID[SIGN].Next=First[x]; First[x]=SIGN++;}int Jude(int x,int y)/*查找与X是否与Y相连*/{ int i; for(i=First[x];i!=0;i=ID[i].Next) //查找与该点相关的点 { if(ID[i].TO==y)return 0; } return 1;}int ToPoSort(int N,int Num[],int K)/*拓扑排序,邻接表*/{ int i,j,k; for(j=0;j<N;j++) { for(i=1;i<=N;i++) { if(InD[i]==0) { InD[i]--; Num[j]=i; for(k=First[i];k!=0;k=ID[k].Next) { InD[ID[k].TO]--; } break; } } if(i>N)break; } if(j>=K)return 1; else return 0;}int main(){ int M,N,K,i; int a,b; int Num[MAX]; while(scanf("%d%d%d",&N,&M,&K)!=EOF) { for(i=1;i<=N;i++){First[i]=0;InD[i]=0;} for(i=0,SIGN=1;i<M;i++) { scanf("%d%d",&a,&b);a+=1;b+=1; Add_E(a,b); } if(ToPoSort(N,Num,K))/*拓扑排序*/ { for(i=0;i<K;i++) { if(i!=0)putchar(32); printf("%d",Num[i]-1); }putchar(10); } else printf("-1\n"); } return 0;}
B - 小Y上学记——小Y的玩偶
Problem Description
小Y最喜欢拆拆拆了~尽管他不一定能装回去。
小Y有一个很可爱的积木玩偶,是由一块一块积木拼接而成,现在小Y想把这个积木玩偶拆拆拆。
每一块积木玩偶都有一个耐久值,想把一块积木拆出来,小Y需要付出的能量就是和它直接拼接的所有积木的耐久值之和。
小Y很懒的~他想知道把这个玩偶全部拆好,最少需要付出多少能量?
Input
多组数据,每组数据首先是一个整数n表示积木块数。(0<n<=1000)
接下来一行包含n个整数,表示每块积木的耐久值a[i](0<=a[i]<=100000)。
接下来是n行,第i行代表第i块积木的连接情况。
每一行首先是一个整数k,表示这块积木与k块积木相连,接下来是k个整数,代表与这块积木相连的积木标号(标号从0开始)
保证连接情况合法。
Output
Sample Input
410 20 30 402 1 32 0 21 11 04100 100 100 1001 13 0 2 32 1 32 1 2740 10 20 10 20 80 404 2 3 4 51 42 0 35 0 2 4 5 64 0 1 3 62 0 32 3 4
Sample Output
40400160
Hint
对于第一组数据,首先拆掉第2块积木,需要20能量,然后拆掉第1块积木,需要10能量,接着拆掉第3块积木,需要10能量,最后只剩下第0块了,不需要能量了。总共需要40点能量。
对于第二组数据,无论怎么拆除,都是需要400点能量。
AC code:
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<queue>#include<math.h>#include<vector>#include<map>#include<set>#include<cmath>#include<string>#include<algorithm>#include<iostream>#define LL long long #define exp 1e-10#define MAXN 1000010using namespace std;const int INF=0x3f3f3f3f;const int N = 100005;const int mod = 1000000007;int n,k,m,mi;int p[MAXN]; struct node{int v;int id;}a[MAXN];int b[MAXN];bool cmp(node a,node b){return a.v>b.v;}vector<int>vec[MAXN];bool vis[MAXN];LL ans,mm;int main(){//freopen("D:\in.txt","r",stdin);int i,j,t;while(scanf("%d",&n)!=EOF){for(i=0;i<n;i++){scanf("%d",&a[i].v);a[i].id=i;}sort(a,a+n,cmp);for(i=0;i<n;i++)b[a[i].id]=i;memset(p,0,sizeof(p));memset(vis,false,sizeof(vis));for(i=0;i<n;i++)vec[i].clear();mm=-INF;mi=0;for(i=0;i<n;i++){scanf("%d",&k);while(k--){scanf("%d",&t);vec[i].push_back(t);p[i]+=a[b[t]].v;}}ans=0;for(j=0;j<n-1;j++){mi=a[j].id;ans+=p[mi];for(i=0;i<vec[mi].size();i++)//更新连接的点{p[vec[mi][i]]-=a[b[mi]].v;}a[b[mi]].v=0;//0表示已删除,不再对与它连接的点有关系,即“惰性删除”}printf("%lld\n",ans);}return 0;}
C - 小Y上学记——认识新同学
Problem Description
小Y来到了一个新的班级,新的集体,第一件事肯定是要去认识新同学。
然而想认识全班同学,所需要的代价是很大的,所以小Y想让代价尽可能小。
认识新同学有两种办法,一种是直接去认识,另一种是通过已经认识的同学去认识新同学。
小Y想知道最小代价是多少呢?
Input
多组数据,每组数据首先是一个N,表示新的班级的同学数(包括小Y,2<=N<=1000)
接下来是N-1个整数,表示小Y直接认识第i名同学所需要的代价。
接下来是一个N-1阶矩阵,其中第i行第j列表示通过第i名同学认识第j名同学的代价。
其中保证对角线为0,且保证对称.
所有代价均为不超过1000的正整数。
Output
Sample Input
32 40 11 042 4 30 1 21 0 12 1 0
Sample Output
34
编程思想:根据题意,可抽象成求一颗最小生成树。这里采用利用并查集构造最小生成树的克鲁斯卡尔算法实现。
AC code:
#include<iostream>#include<algorithm>#include<cmath>#include<cstring>#include<cstdio>#include<queue>#include<vector>#define LL long long#define MAXN 1000010using namespace std;const int INF=0x3f3f3f3f;struct node{ int u; int v; int w;}e[MAXN];int point[MAXN],f[MAXN];int ans,n,p,cnt;bool cmp(node a,node b){ return a.w<b.w;}void init(int n){ for(int i=1;i<=n;i++) f[i]=i;}int fin(int root){ int son,tem; son=root; while(root!=f[root]) { root=f[root]; } while(son!=root) { tem=f[son]; f[son]=root; son=tem; } return root;}bool join(int r1,int r2){ int x=fin(r1); int y=fin(r2); if(x!=y) { f[x]=y; return true; } return false;}int clu(){ ans=0; for(int i=1;i<=p;i++) { int u=e[i].u; int v=e[i].v; if(join(u,v)) { ans+=e[i].w; cnt++; } } return ans;}int main(){ //freopen("D:\in.txt","r",stdin); int i,j,l,tt; while(scanf("%d",&n)!=EOF) { p=0; for(i=2;i<=n;i++) { p++; e[p].u=1; e[p].v=i; scanf("%d",&e[p].w); } for(i=2;i<=n;i++) { for(j=2;j<=n;j++) { scanf("%d",&tt); p++; if(i==j) { tt=INF; } e[p].u=i; e[p].v=j; e[p].w=tt; } } sort(e+1,e+p+1,cmp); cnt=0; init(n); cout<<clu()<<endl; } return 0;}
- XMUT 简单图论专场(拓扑排序、最小生成树、贪心)
- 拓扑排序+最小生成树
- CUGB图论专场:C - Tangled in Cables(最小生成树kruscal)
- 第二周---最小生成树(Kruskal,Prim)、拓扑排序
- 最小生成树和拓扑排序
- 图:图的应用(最小生成树、拓扑排序、关键路径)
- 数据结构学习笔记(十)-图的最小生成树与拓扑排序
- 图的遍历(dfs、bfs、最短路、最小生成树、拓扑排序)
- XMUT acdream DP专场
- 20131111:图的应用:最小生成树;拓扑排序;最短路径;最小树形图
- XMUT acdream 数据结构专场 C题(单调栈)
- 并查集和拓扑排序加最小生成树
- 最短路,最小生成树,及拓扑排序模板整理
- 数据结构:图的存储、图的遍历、最小生成树、最短路径、拓扑排序
- 数据结构实验报告-图算法-最小生成树-最短路-拓扑排序-搜索
- 拓扑排序 详解 + 并查集 详解 + 最小生成树(MST)详解
- 2017.4.3 机房测试 (并查集,最短路,拓扑排序,最小生成树)
- 贪心-最小生成树
- jQuery操作checkBox(多选框)
- android获取屏幕尺寸、密度(判断手机屏幕类型)
- 为vs2015配置opencv
- PhotoView开源项目剖析
- mysql的备份与恢复(基本概念)
- XMUT 简单图论专场(拓扑排序、最小生成树、贪心)
- POJ 1003
- MyBatis 和 MyBatis-Spring 官方文档
- JS sort()方法排序问题修正方式
- 存储引擎概念(基本概念)
- ikjng;lnesgms;egnmsoegnlk;g
- 【POJ 2442】Sequence
- bt5安装nessus
- lkxlfhm';hrml'hmcfmhm';hmd;