Summer Holiday
Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6068 Accepted Submission(s): 2607
Problem Description
To see a World in a Grain of Sand
And a Heaven in a Wild Flower,
Hold Infinity in the palm of your hand
And Eternity in an hour.
—— William Blake
听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?
And a Heaven in a Wild Flower,
Hold Infinity in the palm of your hand
And Eternity in an hour.
—— William Blake
听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?
Input
多组测试数组,以EOF结束。
第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。
接下一行有N个整数,表示Wiskey联系第i个人的电话费用。
接着有M行,每行有两个整数X,Y,表示X能联系到Y,但是不表示Y也能联系X。
第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。
接下一行有N个整数,表示Wiskey联系第i个人的电话费用。
接着有M行,每行有两个整数X,Y,表示X能联系到Y,但是不表示Y也能联系X。
Output
输出最小联系人数和最小花费。
每个CASE输出答案一行。
每个CASE输出答案一行。
Sample Input
12 16 2 2 2 2 2 2 2 2 2 2 2 2 1 3 3 2 2 1 3 4 2 4 3 5 5 4 4 6 6 4 7 4 7 12 7 8 8 7 8 9 10 9 11 10
Sample Output
3 6
Author
威士忌
Source
Recommend
一道基础tarjan缩点题需要注意贪心的地方
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e4 + 10;
const int maxm = 5e4 + 10;
int head[maxn];
int dfn[maxn];
int low[maxn];
bool vis[maxn];
int colour[maxn];
int e[maxn];
int e1[maxn];
int indu[maxn];
int outdu[maxn];
int dist[maxn];
int tot;
int tot1;
int dex;
int cnt;
int t;
int n, m;
int ans;
int sum;
set<int> r;
struct node{
int to;
int next;
int from;
node() {}
node(int a, int b, int c) : to(a), next(b), from(c) {}
}edge[maxm], edge1[maxm];
void edgeadd(int a, int b){
edge[tot] = node(b, head[a], a);
head[a] = tot++;
}
void edgeadd1(int a, int b){
edge1[tot1] = node(b, head[a], a);
head[a] = tot1++;
}
void init(){
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(dfn, 0, sizeof(dfn));
memset(indu, 0, sizeof(indu));
memset(outdu, 0, sizeof(outdu));
tot = 0;
tot1 = 0;
dex = 0;
ans = 0;
sum = 0;
}
stack<int> s;
void tarjan(int u){
dfn[u] = low[u] = ++dex;
s.push(u);
vis[u] = 1;
for(int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v]){
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]){
sum++;
//cout << sum <<endl;
while(1){
int now = s.top();
//cout << now << endl;
colour[now] = sum;
//e1[sum] = min(e[now], e1[sum]);
e1[sum] = e[u];
s.pop();
vis[now] = 0;
if(now == u) break;
}
}
}
int main(){
ios::sync_with_stdio(false);
while(cin >> n >> m){
init();
for(int i = 1; i <= n; i++)
cin >> e[i];
int x, y;
for(int i = 1; i <= m; i++){
cin >> x >> y;
edgeadd(x, y);
}
for(int i = 1; i <= n; i++){
if(!dfn[i])
tarjan(i);
}
memset(head, -1, sizeof(head));
r.clear();
for(int i = 0; i < m; i++){
int o, g;
o = colour[edge[i].from];
g = colour[edge[i].to];
if(o != g){
edgeadd1(o, g);
indu[g]++;
outdu[o]++;
}
}
for(int i = 1; i <= n; i++){//贪心让每个连通块取其中代价最小的点
if(e1[colour[i]] > e[i])
e1[colour[i]] = e[i];
}
int an1 = 0;
int an2 = 0;
int y1 = 0;
int y2 = 0;
for(int i = 1; i <= sum; i++){
if(!indu[i]){
an1++;
y1 += e1[i];
}
}
cout << an1 << " ";
cout << y1 << endl;
}
return 0;
}