【停课集训 10.14】【#4 training】

 

ZOJ 2966
A - Build The Electric System
Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu

Description

In last winter, there was a big snow storm in South China. The electric system was damaged seriously. Lots of power lines were broken and lots of villages lost contact with the main power grid. The government wants to reconstruct the electric system as soon as possible. So, as a professional programmer, you are asked to write a program to calculate the minimum cost to reconstruct the power lines to make sure there's at least one way between every two villages.

Input

Standard input will contain multiple test cases. The first line of the input is a single integer T (1 <= T <= 50) which is the number of test cases. And it will be followed by T consecutive test cases.

In each test case, the first line contains two positive integers N and E (2 <= N <= 500, N <= E <= N * (N - 1) / 2), representing the number of the villages and the number of the original power lines between villages. There follow E lines, and each of them contains three integers, ABK (0 <= AB < N, 0 <= K < 1000). A and B respectively means the index of the starting village and ending village of the power line. If K is 0, it means this line still works fine after the snow storm. If K is a positive integer, it means this line will cost K to reconstruct. There will be at most one line between any two villages, and there will not be any line from one village to itself.

Output

For each test case in the input, there's only one line that contains the minimum cost to recover the electric system to make sure that there's at least one way between every two villages.

Sample Input

1
3 3
0 1 5
0 2 0
1 2 9

Sample Output

5

这道题裸的最小生成树。。唯一坑的是点从0开始!!刚开始我从1开始WA了2次。。以后读题要仔细

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

struct edge{
	int u,v,w;
	bool operator <(const edge &a)const{return this -> w < a.w;}
}e[125000 + 5];
int T;
int fa[500 + 5];
int n,E;
int find(int x){
	return x == fa[x] ? x : fa[x] = find(fa[x]);
}
int kruskal(){
	int ans = 0;
	for(int i = 1,count = 1; i <= E && count <= n; ++i){
		int x = find(e[i].u),y = find(e[i].v);
		if(x != y){
			fa[x] = y;
			count++;
			ans += e[i].w;
		}
	}
	return ans;
}
int main()
{
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n, &E);
		for(int i = 0; i < n; ++i)fa[i] = i;
		for(int i = 1; i <= E; ++i){
			scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
		}
		sort(e + 1, e + 1 + E);
		printf("%d\n",kruskal());
	}
	return 0;
}

POJ 1062
B - 昂贵的聘礼
Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u

Description

年轻的探险家来到了一个印第安部落里。在那里他和酋长的女儿相爱了,于是便向酋长去求亲。酋长要他用10000个金币作为聘礼才答应把女儿嫁给他。探险家拿不出这么多金币,便请求酋长降低要求。酋长说:"嗯,如果你能够替我弄到大祭司的皮袄,我可以只要8000金币。如果你能够弄来他的水晶球,那么只要5000金币就行了。"探险家就跑到大祭司那里,向他要求皮袄或水晶球,大祭司要他用金币来换,或者替他弄来其他的东西,他可以降低价格。探险家于是又跑到其他地方,其他人也提出了类似的要求,或者直接用金币换,或者找到其他东西就可以降低价格。不过探险家没必要用多样东西去换一样东西,因为不会得到更低的价格。探险家现在很需要你的帮忙,让他用最少的金币娶到自己的心上人。另外他要告诉你的是,在这个部落里,等级观念十分森严。地位差距超过一定限制的两个人之间不会进行任何形式的直接接触,包括交易。他是一个外来人,所以可以不受这些限制。但是如果他和某个地位较低的人进行了交易,地位较高的的人不会再和他交易,他们认为这样等于是间接接触,反过来也一样。因此你需要在考虑所有的情况以后给他提供一个最好的方案。 
为了方便起见,我们把所有的物品从1开始进行编号,酋长的允诺也看作一个物品,并且编号总是1。每个物品都有对应的价格P,主人的地位等级L,以及一系列的替代品Ti和该替代品所对应的"优惠"Vi。如果两人地位等级差距超过了M,就不能"间接交易"。你必须根据这些数据来计算出探险家最少需要多少金币才能娶到酋长的女儿。 

Input

输入第一行是两个整数M,N(1 <= N <= 100),依次表示地位等级差距限制和物品的总数。接下来按照编号从小到大依次给出了N个物品的描述。每个物品的描述开头是三个非负整数P、L、X(X < N),依次表示该物品的价格、主人的地位等级和替代品总数。接下来X行每行包括两个整数T和V,分别表示替代品的编号和"优惠价格"。

Output

输出最少需要的金币数。

Sample Input

1 4
10000 3 2
2 8000
3 5000
1000 2 1
4 200
3000 2 1
4 200
50 2 0

Sample Output

5250
这道题反正是把我坑了无数次,提交上去WA了无数次,思路倒是简单,我是用dijkstra做的,我们可以把物品1当做终点,然后以每个物品做起点来做最短路,将可以优惠的物品之间建一条边,权值为优惠的价格,反向建边,比如从1的10000元可以用2来优惠成8000元,就建一条从2到1的权值为5000的有向边,这样就是标准的最短路了,就是多了个等级,那么只要最短路上的等级最小的点与终点的差不超过m,那么就可以,不行的就忽略,每次更新最小值,如果不能到终点就是为终点的权值。。。就是判等级那里最恶心。。因为那里WA调了好久QAQ。。

#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;

struct egde{
	int v,w,next;
}e[100*100 + 5];
typedef pair<int ,int>pii;
bool vis[100 + 5];
int p[100 + 5],l[100 + 5],x[100 + 5];
int dis[100 + 5];
priority_queue<pii, vector<pii>, greater<pii> >q;
int ans = 0x3f3f3f3f;
int m,n;
int head[100 + 5],k = 1;

void adde(int u,int v,int w)
{
	e[k].v = v;
	e[k].w = w;
	e[k].next = head[u];
	head[u] = k++;
}
int abs(int a){
	return a <= 0 ? -a : a;
}
int dijkstra(int x)
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[x] = p[x];q.push(make_pair(dis[x],x));vis[x] = 1;
	while(q.size()){
		int u = q.top().second;q.pop();
		for(int i = head[u]; i ; i = e[i].next){
			int v = e[i].v;
			if(abs(l[u] - l[v]) <= m && abs(l[x] - l[v]) <= m && (abs(l[v] - l[1]) <= m) && abs(l[u] - l[1]) <= m){
				if(dis[v] > dis[u] + e[i].w)
				dis[v] = dis[u] + e[i].w;
				if(!vis[v]){
					vis[v] = 1;
					q.push(make_pair(dis[v],v));
				}
			}
		}
	}
	return dis[1];
}
int main()
{
	while(~scanf("%d%d",&m,&n)){
		ans = 0x3f3f3f3f;
		for(int i = 1; i <= n; ++i){
			scanf("%d%d%d",&p[i],&l[i],&x[i]);
			for(int j = 1; j <= x[i]; ++j){
				int t,v;
				scanf("%d%d",&t,&v);
				adde(t,i,v);
			}
		}
		for(int i = 1; i <= n; ++i)
		ans = min(ans,dijkstra(i));
		if(ans == 0x3f3f3f3f)printf("%d\n",p[1]);
		else printf("%d\n",ans);
	}
	return 0;
}

UVA 11770
C - Lighting Away
Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %lld

Ronju is a night-guard at the “Lavish office buildings Ltd.” headquarters. The office has a large grassfield in front of the building. So every day, when Ronju comes to duty at the evening, it is his dutyto turn on all the lights in the field. However, given the large size of the field and the large number oflights, it is very tiring for him to walk to each and every individual light to turn it on.So he has devised an ingenious plan — he will swap the switches for light-sensitive triggers. Alocal electronic store nearby sells these funny trigger switches at a very cheap price. Once installed ata light-post, it will automatically turn that light on whenever it can sense some other light lightingup nearby. So from now on, Ronju can just manually flip a few switches, and the light from thosewill trigger nearby sensors, which will in turn light up some more lights nearby, and so on, graduallylighting up the whole field.Now Ronju wonders: how many switches does he have to flip manually for this?

Input

The input starts with an integer T, the number of test cases to follow. Each test case will start withtwo integers N (1 ≤ N ≤ 10000) and M (0 ≤ M ≤ 100000), where N is the number of lights in thefield, and M more lines of input follows in this input case. Each of these extra M lines will have twointegers a and b separated by a space, where 1 ≤ a, b ≤ N, indicating that if the light a lights up, itwill trigger the light b to turn on as well (according to their distance, brightness, sensor sensitivity,orientation and other complicated factors).Finally, every test case in the input will be followed by a blank line.

Output

For each input test case, the output must be a single line of the format ‘Case k: c’ where k is thecase number starting with 1, and c is the minimum number of lights that Ronju must turn on manuallybefore all the lights in the whole field gets lit up.

Sample Input

2

5 4

1 2

1 3

3 4

5 3

4 4

1 2

1 3

4 2

4 3

Sample Output

Case 1: 2

Case 2: 2

这道题直接tarjan+缩点,然后找入度为0的点的个数就好了,会了tarjan的就是一道裸题,不会的。。。去学吧

#include<cstdio>
#include<iostream>
#include<vector>
#include<stack>
#include<cstring>
#define mem(x,a) memset(x,a,sizeof(x))
using namespace std;

int T;
int n,m;
vector<int >e[10000 + 5];
bool vis1[10000 + 5];//标记是否访问过 
bool vis2[10000 + 5];//标记是否在栈中 
int dfn[10000 + 5],low[10000 + 5];//dfn[u]为到u的次序数,low[u]为能直接或间接到达的次序数
int belong[10000 + 5];//缩点后每个点属于哪个点 
int in[10000 + 5];
stack<int >q;
int id = 1,node = 0;;

void init(){
	for(int i = 1;i <= n; ++i)
	e[i].clear();
	node = 0;
	id = 1;
	mem(vis1,0);
	mem(vis2,0);
	mem(dfn,0);
	mem(low,0);
	mem(in,0);
	while(q.size())q.pop();
}
void tarjan(int u){
	dfn[u] = low[u] = id++;
	vis1[u] = 1;q.push(u);vis2[u] = 1;
	for(int i = 0; i < e[u].size(); ++i){
		int v = e[u][i];
		if(!vis1[v]){
			tarjan(v);
			low[u] = min(low[v],low[u]);
		}
		else if(vis2[v]) low[u] = min(dfn[v],low[u]);
	}
	if(low[u] == dfn[u]){
		node++;
		while(1){
			int tmp = q.top();q.pop();
			vis2[tmp] = 0;
			belong[tmp] = node;
			if(tmp == u)break;
		}
	}
}
int main()
{
	scanf("%d",&T);
	int cnt = 1;
	while(T--){
		int ans = 0;
		scanf("%d%d",&n,&m);
		init();
		for(int i = 1; i <= m; ++i){
			int a,b;
			scanf("%d%d",&a,&b);
			e[a].push_back(b);
		}
		for(int i = 1; i <= n; ++i){
			if(!vis1[i])
			tarjan(i);
		}
		for(int i = 1; i <= n; ++i){
			for(int j = 0; j < e[i].size(); j++){
				int v = e[i][j];
				if(belong[i] != belong[v])
				in[belong[v]]++;
			}
		}
		for(int i = 1; i <= node; ++i){
			if(!in[i])ans++;
		}
		printf("Case %d: %d\n",cnt++,ans);
	}
	return 0;
}

UVALive 6266
D - Admiral
Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %ll

Michiel Adriaenszoon de Ruyter is the most famous admiral in Dutch history and is well known for hisrole in the Anglo-Dutch Wars of the 17th century. De Ruyter personally commanded a flagship andissued commands to allied warships during naval battles.In De Ruyter’s time, graph theory had just been invented and the admiral used it to his greatadvantage in planning his naval battles. Waypoints at sea are represented by vertices, and possiblepassages from one waypoint to another are represented as directed edges. Given any two waypointsW1 and W2 , there is at most one passage W1 → W2 . Each directed edge is marked with the numberof cannonballs that need to be fired in order to safely move a ship along that edge, sinking the enemyships encountered along the way.One of De Ruyter’s most successful tactics was the De Ruyter Manoeuvre. Here, two warships startat the same waypoint, and split up and fight their way through the enemy fleet, joining up again at adestination waypoint. The manoeuvre prescribes that the two warships take disjunct routes, meaningthat they must not visit the same waypoint (other than the start and end-points), or use the samepassage during the battle.Being Dutch, Admiral De Ruyter did not like to waste money; in 17th century naval warfare, thismeant firing as few expensive cannonballs as possible.Figure 1: A particular instance of De Ruyter’s tactic, visualised as a graph. Two ships (‘red’and ‘blue’) move from a shared starting point (1) to a shared endpoint (6). The red ship’s route is1 → 3 → 6 (firing 33 canonballs along the way); the blue ship’s route is 1 → 2 → 5 → 4 → 6 (firing53 canonballs along the way). In total, 86 canonballs are fired during the manoeuvre. Except for thestart- and end-point, no vertices or edges are visited by both ships.

Input

For each test case, the input consists of:• A line containing two integers v (3 ≤ v ≤ 1000) and e (3 ≤ e ≤ 10000), the number of waypointsand passages, respectively.• Then, e lines follow: for each passage, a line containing three integers:1. ai (1 ≤ ai ≤ v), the starting-point of a passage, which is represented by a waypoint;2. bi (1 ≤ bi ≤ v) and (ai ̸= bi), the end-point of a passage, which is represented by a waypoint.All passages are directed passages;3. ci (1 ≤ ci ≤ 100), the number of cannonballs that are fired when travelling along this passage.The starting waypoint is 1 and the destination waypoint is v. There are always at least two disjunctroutes from waypoint 1 to waypoint v.

Output

For each test case, the output consists of a single positive integer: the smallest possible sum of cannonballsfired by both ships when reaching the destination waypoint.

Sample Input

6 11

1 2 23

1 3 12

1 4 99

2 5 17

2 6 73

3 5 3

3 6 21

4 6 8

5 2 33

5 4 5

6 5 20

Sample Output

86

这道题是最小费用最大流,由于1,v都要经过两次,所以为最大流,这道题可以拆点,将一个点拆为入点和出点,在建一条由入点到出点的流量限制为1的有向边,这样就是这个点走后流量为0,就不能走了,那么1,v就是流量为2的两个点;

首先构造带权有向图w(f)。w(f)中路径pre上的各边权之和即为原图G中相应可改进路pre的费用。w(f)的最短路即为G中的最小费用可改进路。在w(f)中寻找最短路,若存在最短路,则得到G中相应的可改进路p,调整p,直到不存在最短路

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define mem(x,a) memset(x,a,sizeof(x))
using namespace std;

const int inf = 0x3f3f3f3f;
struct edge{
	int u,v,f,c,next;
}e[50000 + 5];
bool vis[1000 * 2 + 5];
int pre[1000 * 2 + 5];//记录路径 
int head[1000 * 2 + 5], k = 0;
int dis[1000 * 2 + 5];//代价 
int n,m,S,T;

void init(){
	mem(head,-1);
	mem(pre,0);
	k = 0;
}
void adde(int u,int v,int c,int f){//起点,终点,代价,流量 
	e[k] = (edge){u,v,f,c,head[u]};
	head[u] = k++;
	e[k] = (edge){v,u,0,-c,head[v]};//后向弧,正向弧编号 ^ 1 
	head[v] = k++;
}
bool spfa(){
	mem(vis,0);
	mem(dis,0x3f);
	queue<int >q;
	dis[S] = 0;q.push(S);
	while(q.size()){
		int u = q.front();q.pop();
		vis[u] = 0;
		for(int i = head[u]; i != -1 ; i = e[i].next){
			int v = e[i].v;
			if(e[i].f && dis[v] > dis[u] + e[i].c){
				pre[v] = i;
				dis[v] = e[i].c + dis[u];
				if(!vis[v]){
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
	return dis[T] != inf;
}
void work(){
	int cost = 0;
	while(spfa()){//不断找最短路直到不能找到为止,若存在最短路,则得到图中中相应的可改进路pre 
		int a = inf;
		for(int i = T; i != S; i = e[pre[i]].u){
			a = min(a,e[pre[i]].f);
		}
		for(int i = T; i != S; i = e[pre[i]].u){
			e[pre[i]].f -= a;
			e[pre[i] ^ 1].f += a;//后向弧流量加 
		}
		cost += a * dis[T];
	}
	printf("%d\n",cost);
}
int main()
{
	while(~scanf("%d%d",&n,&m)){
		init();
		S = 1,T = 2 * n;//拆点,入点和出点,入点为i * 2 - 1,出点为i * 2 
		//入点和出点相连,中间加流量限制 
		adde(1, 2, 0, 2);
		adde(n * 2 - 1, n * 2, 0, 2);//起点,终点的流量为2,其余点为1; 
		for(int i = 2; i < n; ++i)adde(i * 2 - 1, i * 2, 0, 1);
		for(int i = 1; i <= m; ++i){
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			adde(a * 2, b * 2 - 1, c, 1);//a的出点和b的入点相连 
		}
		work();
	}
	return 0;
} 




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值