2017 Multi-University Training Contest - Team 10

1008

题意:n个结点,m个猴子,保证是一颗树且联通,要求消除尽可能多的边使得每一块至少有两只猴子,问最后还剩下多少条边

思路:发现可知,如果我们能将树剪成尽可能多的 只有两个结点组成的树,那么对答案就是最优的

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
const int BUFSIZE = 1e8;
char Buf[BUFSIZE + 1], *buf = Buf;
template <class T>
void scan(T & a) {
	for(a = 0; *buf < '0' || *buf > '9'; buf++);
	while(*buf >= '0' && *buf <= '9'){a = a * 10 + (*buf - '0'); buf++; }	
}
int n, m;
bool f[qq];
vector<int> G[qq];
int k;
void Dfs(int u, int fa) {
	int sz = G[u].size();
	for(int i = 0; i < sz; ++i) {
		int v = G[u][i];
		if(v == fa)	continue;
		Dfs(v, u);
	}
	if(!f[u] && !f[fa]) {
		k++;
		f[u] = f[fa] = true;
	}
}

int main(){
	fread(Buf, 1, BUFSIZE, stdin);
	int t;	scan(t);
	while(t--) {
		scan(n), scan(m);
		for(int i = 0; i <= n; ++i) {
			G[i].clear();
		}
		int u;
		for(int i = 2; i <= n; ++i) {
			scan(u);
			G[u].pb(i), G[i].pb(u);
		}
		k = 0;
		mst(f, false);
		Dfs(1, -1);
		if(2 * k >= m) {
			printf("%d\n", (m + 1) / 2);
		} else {
			printf("%d\n", m - k);
		}
	}		
	return 0;
}



1010

题意:给出n个任务的开始时间和结束时间,要求每一个任务来的时候都有机器可以运行,现在让你求出最少使用几台机器,并且求出所有机器工作的最少时间的和

每台机器的工作时间是等于 关闭机器的时间减去打开机器的时间,机器打开后直到属于它的最后一个任务结束才关闭

2

2 3

3 4

此时只需要一台机器

思路:最少使用多少台机器很好求,关键在于怎么求出最少时间,我们可以这样想象,对于一个新来的任务,此时任务的开始时间要尽可能逼近当前所有机器中最慢结束的那一个

比如

1 2

1 3

以上是两台机器执行的任务

此时来了一个

3 4

它应该被接在 1 3的那台机器

此时才能保证最小时间

所以我们对任务按开始时间排序,在set里面维护每个机器当前任务的结束时间,对每个任务开始的时间找一个最接近的结束时间即可

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
struct Node {
	int l, r;
}node[qq];
bool cmp(const Node &a, const Node &b) {
	if(a.l == b.l)	return a.r < b.r;
	return a.l < b.l;
}
int n;
multiset<int> st;
multiset<int>::iterator it;

int main(){
	int t;	scanf("%d", &t);
	while(t--) {
		st.clear();
		scanf("%d", &n);
		for(int i = 0; i < n; ++i) {
			scanf("%d%d", &node[i].l, &node[i].r);
		}
		sort(node, node + n, cmp);
		LL sum = node[0].r - node[0].l;
		st.insert(node[0].r);
		for(int i = 1; i < n; ++i) {
			it = st.lower_bound(node[i].l);
			if(it == st.end()) {
				--it;
				sum += node[i].r - *it;
				st.insert(node[i].r);
				st.erase(it);
			} else if(it == st.begin()) {
				if(node[i].l == *it) {
					sum += (node[i].r - *it);
					st.insert(node[i].r);
					st.erase(it);
				} else {
					sum += node[i].r - node[i].l;
					st.insert(node[i].r);
				}
			} else {
				if(*it == node[i].l) {
					sum += (node[i].r - *it);
					st.insert(node[i].r);
					st.erase(it);
				} else {
					--it;
					sum += (node[i].r - *it);
					st.insert(node[i].r);
					st.erase(it);
				}
			}
		}
		printf("%d %lld\n", (int)st.size(), sum);
	}
	return 0;
}

1011

题意:求1到n的次短路的大小,但是注意这里的次短路可以有环

思路:分两种情况考虑,存在环与不存在环,首先不存在环的情况就是次短路,存在环的情况无非就是最短路的路径中某一条边走了三次,这里求出最短路路径然后求一下就好,次短路的情况就是把最短路经过的点不考虑,求出1~i i~n的最短路即可

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 1e5 + 10;
const LL INF = 1e15 + 10;
vector<int> G[qq];
vector<LL> f[qq];
LL dis1[qq], dis2[qq];
int pre[qq];
int dis[qq];
bool vis[qq];
int n, m;
void Spfa(int s, LL *p) {
	queue<int> Q;
	Q.push(s);
	for(int i = 0; i <= n; ++i) {
		p[i] = INF;
		vis[i] = false;
	}
	p[s] = 0;
	vis[s] = true;
	while(!Q.empty()) {
		int u = Q.front();
		Q.pop();
		vis[u] = false;
		for(int i = 0; i < (int)G[u].size(); ++i) {
			int v = G[u][i];
			if(p[u] + f[u][i] < p[v]) {
				p[v] = p[u] + f[u][i];
				pre[v] = u;
				dis[v] = f[u][i];
				if(!vis[v]) {
					Q.push(v);
					vis[v] = true;
				}
			}
		}
	}
}
void Init() {
	for(int i = 0; i <= n; ++i) {
		G[i].clear();
		f[i].clear();
	}
}
bool vt[qq];

int main(){
	int t;	scanf("%d", &t);
	while(t--) {
		scanf("%d%d", &n, &m);
		Init();
		int a, b;	LL c;
		for(int i = 0; i < m; ++i) {
			scanf("%d%d%lld", &a, &b, &c);
			G[a].pb(b), G[b].pb(a);
			f[a].pb(c), f[b].pb(c);
		}
		Spfa(1, dis1);
		LL minx = dis1[n];
//		printf("%lld\n", minx);
		LL ans = INF;
		for(int i = 1; i <= n; ++i) {
			vt[i] = false;
		}
		int v = n;
		vt[1] = vt[n] = true;
		do {
			ans = min(ans, minx + dis[v] * 2LL);
			v = pre[v];
			vt[v] = true;
		} while(v != 1);
		Spfa(n, dis2);
		for(int i = 2; i < n; ++i) {
			if(vt[i])	continue;
			if(dis1[i] + dis2[i] >= minx) {
				ans = min(ans, dis1[i] + dis2[i]);
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值