[noip模拟赛2017.7.14]

问题名称 文件名 输入文件 输出文件 时限 分值
修复公路 road road.in road.out 1s 100
轰炸 danger danger.in danger.out 1s 100
最短路 short short.in short.out 1s 100

修复公路(road)

问题描述

A 地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些 公路。 给出 A 地区的村庄数 N,和公路数 M,公路是双向的。并告诉你每条公路的连着哪两个 村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早 什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)

数据输入

第 1 行两个正整数 N,M(N<=1000,M<=100000) 下面 M 行,每行 3 个正整数 x, y, t,告诉你这条公路连着 x,y 两个村庄,在时间 t 时 能修复完成这条公路。(x<=N,y<=N,t<=100000)

数据输出

如果全部公路修复完毕仍然存在两个村庄无法通车,则输出-1,否则输出最早什么时候 任意两个村庄能够通车。

样例输入

4 4

1 2 6

1 3 4

1 4 5

4 2 3

样例输出

5

题解

最小生成树模板题

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;

int n,m;
struct Edge{
	int a,b,t;
	Edge(int x=0,int y=0,int z=0)
		{a=x;b=y;t=z;}
}e[100100];
bool cmp(Edge x,Edge y){
	return x.t<y.t;
}

int Fa[1010];
void pre(){
	for(int i=1;i<=n;i++)
		Fa[i]=i;
}
int findf(int x){
	return x==Fa[x]?x:Fa[x]=findf(Fa[x]);
}
void mergef(int x,int y){
	Fa[findf(x)]=findf(y);
}
int ans;
int main(){
	freopen("road.in","r",stdin);
	freopen("road.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		e[i]=Edge(x,y,z);
	}
	sort(e+1,e+1+m,cmp);
	pre();
	for(int i=1;i<=m;i++){
		int x=e[i].a,y=e[i].b;
		if(findf(x)!=findf(y)){
			mergef(x,y);
			ans=max(e[i].t,ans);
		}
	}
	for(int i=2;i<=n;i++)
		if(findf(i)!=findf(1){
			ans=-1;
			break;
		}
	printf("%d",ans);
}
 

轰炸(danger)

问题描述

小 y 是苏联的总书记。 苏联有 n 个城市,某些城市之间修筑了公路。任意两个城市都可以通过公路直接或者间 接到达。 小 y 发现有些公路被毁坏之后会造成某两个城市之间无法互相通过公路到达。这样的公 路就被称为 dangerous pavement。 为了防止美帝国对 dangerous pavement 进行轰炸,造成某些城市的地面运输中断,小 y 决定在所有的 dangerous pavement 驻扎重兵。可是到底哪些是 dangerous pavement 呢? 你的任务就是找出所有这样的公路。

输入格式

第一行 n,m(1<=n<=150, 1<=m<=5000),分别表示有 n 个城市,总共 m 条公路。 以下 m 行,每行两个整数 a, b,表示城市 a 和城市 b 之间修筑了直接的公路。

输出格式

输出有若干行。 每行包含两个数字 a,b(a<b),表示<a,b>是 dangerous pavement。 请注意:输出时,所有的数对<a,b>必须按照 a 从小到大排序输出;如果 a 相同,则根 据 b 从小到大排序。

输入样例

6 6

1 2

2 3

2 4

3 5

4 5

5 6

输出样例

1 2

5 6

题解

图的割边。。。怎么说呢,tarjan待学

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
#define INF (1<<30)
using namespace std;

int n,m;
int a[10000],b[10000],nt[10000],p[500],cnt=2;
void add(int x,int y){
	a[cnt]=x;b[cnt]=y;
	nt[cnt]=p[x];p[x]=cnt++;
}
int coc[500],t=1;
bool vis[500];
struct edge{
	int a,b;
	edge(int x=0,int y=0){
		a=x;b=y;
	}
}ans[500];int tot;
bool cmp(edge x,edge y){
	if(x.a!=y.a)return x.a<y.a;
	else return x.b<y.b;
}
bool fail[10000];
bool get[10000];
int dfs(int k){
	int rtn=INF;coc[k]=t++;vis[k]=true;
	for(int i=p[k];i;i=nt[i])if(!get[i]){
		get[i]=get[i^1]=true;
		int kk=b[i];int tt;
		if(!vis[kk])tt=dfs(kk);
		else tt=coc[kk];
		if(tt<=coc[k])
			fail[i]=fail[i^1]=true;
		rtn=min(INF,tt);
	}
	return rtn;
}
int main(){
	freopen("danger.in","r",stdin);
	freopen("danger.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}
	dfs(1);
	for(int i=2;i<=m*2+1;i+=2)
		if(!fail[i])
			ans[++tot]=edge(min(a[i],b[i]),max(a[i],b[i]));
	sort(ans+1,ans+1+tot,cmp);
	for(int i=1;i<=tot;i++)
		printf("%d %d
",ans[i].a,ans[i].b);
}

/*
6 6
1 2 
2 3 
2 4 
3 5 
4 5 
5 6
*/

最短路(short)

问题描述

给出 N 个点,M 条无向边的简单图,问所有点对之间的最短路。

数据输入

第 1 行两个正整数 N,M(N<=100,M<=5000) 下面 M 行,每行 3 个正整数 x, y, w,为一条连接顶点 x 与 y 的边权值为 w。 (x<=n, y<=n, w<=1000)

数据输出

包括 N 行,每行 N 个数,第 i 行第 j 个数为点 i 到点 j 的最短路,第 i 行第 i 个数应为 0,数字之间空格隔开。

样例输入

5 10

3 2 1

2 4 7

5 3 4

4 1 2

5 1 8

3 4 10

5 4 9

2 5 2

1 2 1

3 1 10

样例输出:

0 1 2 2 3

1 0 1 3 2

2 1 0 4 3

2 3 4 0 5

3 2 3 5 0

题解

floyd,略

原文地址:https://www.cnblogs.com/Anoxiacxy/p/7184375.html