关闭

HDOJ--1827--Summer Holiday(强连通分量的最小代价连接)

298人阅读 评论(0) 收藏 举报
分类:

Summer Holiday

Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2368    Accepted Submission(s): 1108


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计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?
 

Input
多组测试数组,以EOF结束。
第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。
接下一行有N个整数,表示Wiskey联系第i个人的电话费用。
接着有M行,每行有两个整数X,Y,表示X能联系到Y,但是不表示Y也能联系X。
 

Output
输出最小联系人数和最小花费。
每个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
威士忌
 
思路:就是强连通然后连接强连通分量,找寻到一个最小代价,连通所有的强连通分量。
AC代码:
//两处错误,一处是tarjan算法中的栈定义在了函数内部。 
//第二处错误是solve算法中vector应从j=0处开始遍历。 
#include<stdio.h>
#include<string.h>
#include<stack>
#include<algorithm>
#include<vector>
#define INF 0x3f3f3f
#define MAX 1010*10 //关键还有MAX的大小的确定 
using namespace std;
struct node{//定义邻接表 
	int from,to,next;
}edge[MAX];
int head[MAX],low[MAX],dfn[MAX],cost[MAX];
bool Instack[MAX];
int in[MAX],edgenum;
int scc_cnt,dfs_clock;
int sccno[MAX];
vector<int> NEW[MAX];//储存新图 
vector<int>	scc[MAX];//记录每个强连通内的点。 
int n,m;
stack<int>q;
void init(){//初始化邻接表 
	edgenum=0;
	memset(head,-1,sizeof(head));
}
void addedge(int u,int v){
	node E={u,v,head[u]};
	edge[edgenum]=E;
	head[u]=edgenum++;
}
void getmap(){
	for(int i=1;i<=n;i++)
		scanf("%d",&cost[i]);
	for(int i=0;i<m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		addedge(a,b);
	}
}
void tarjan(int u){//寻找强连通分量 
	int v;
	low[u] = dfn[u] = ++dfs_clock;//更新初始化low和dfn数组 
	q.push(u);
	Instack[u] = true;
	for(int i = head[u]; i != -1; i = edge[i].next)//深搜每一个节点 
	{
		v = edge[i].to; 
		if(!dfn[v])
		{
			tarjan(v);
			low[u] = min(low[u], low[v]);
		}
		else if(Instack[v])
		low[u] = min(low[u], dfn[v]); //构建反向边。 
	}

	if(low[u]==dfn[u]){//满足条件的话增加每一个强连通分量 
		scc_cnt++;
		scc[scc_cnt].clear(); 
		while(1){
			v=q.top();
			sccno[v]=scc_cnt;
			scc[scc_cnt].push_back(v);
			q.pop();
			Instack[v]=false;
			if(u==v)//该强连通分量的所有点都出来的话 就跳出。 
				break;
		}
	}
}
void find_cut()
{
	memset(low, 0, sizeof(low));//初始化寻找祖先的数组 
	memset(dfn, 0, sizeof(dfn));//初始化此时能遍历到的数组 
	memset(sccno, 0, sizeof(sccno));//初始化sccno数组,找到每个强连通的点。 
	memset(Instack, false, sizeof(Instack));
	dfs_clock = scc_cnt = 0;//初始化时间戳和强连通数量。 
	for(int i = 1; i <= n; i++)//遍历每一个节点 
	if(!dfn[i]) tarjan(i);
}
void suodian(){
	memset(in,0,sizeof(in));//初始化入度节点 
	for(int i=0;i<edgenum;i++){
		int u=sccno[edge[i].from];
		int v=sccno[edge[i].to];
		if(u!=v){//构建新图。 
			NEW[u].push_back(v);// 新图的边 
			in[v]++;// //新图中每个scc的入度。 
		}	
	}
}
void solve(){
		int mincost=0,temp;//初始化mincost数值。 
		int cnt=0;
		if(scc_cnt==1){
			sort(cost+1,cost+n+1);
			printf("1 %d\n",cost[1]);
		}
		else{
			for(int i=1;i<=scc_cnt;i++){
				if(in[i])//入度为0的才需要构建新边 
					continue;
				cnt++;
				temp=INF;
				for(int j=0;j<scc[i].size();j++)//遍历的时候这一步是从0开始的 
					temp=min(cost[scc[i][j]],temp);//寻找到连接该强连通分量最小的代价 
				mincost+=temp;
			}
				printf("%d %d\n",cnt,mincost);
				
		}
}
int main(){
	while(scanf("%d%d",&n,&m)!=EOF){
		init();
		getmap();//输入地图 
		find_cut();//寻找强连通分量的数目。 
		suodian();//缩点,构造新图。 
		solve();//解决该问题。 
	}
	return 0;
} 
//历时N天,终于总算是把这道题给解决了。心塞塞。无语了。心好累。 
 


0
0
查看评论

算法之路--最小代价生成树

前言 一个无向连通图的生成树是极小连通子图 这句话是在我学习算法设计的时候看到的,当时学了很多什么无向连同有向连同的,具体的我也记不清了,记得上次说要整理算法模块的,一直没时间整理,心想行动才是最有效的办法。整理得出一句话:一棵生成树的代价是树中各条边上的代价之和且是最小。 贪心法...
  • u013132051
  • u013132051
  • 2016-11-29 12:48
  • 3485

求数列合并最小代价

首先说下题:BOI 2007 Day 2 - Sequence http://www.boi2007.de/en/tasks 对于一个给定的数列A1, A2, A3...An,定义一个操作Reduce(i), 将Ai, A(i+1) 合并为一个元素,其值为Ai与A(i+1)的较大...
  • lingyun310
  • lingyun310
  • 2009-02-06 17:17
  • 730

贪心算法(四)——最小代价生成树

问题描述 n个村庄间架设通信线路,每个村庄间的距离不同,如何架设最节省开销? 这个问题中,村庄可以抽象成节点,村庄之间的距离抽象成带权值的边,要求最节约的架设方案其实就是求如何使用最少的边、最小的权值和将图中所有的节点连接起来。 这就是一个最小代价生成树的问题,可以用Prim算法或kruska...
  • u010425776
  • u010425776
  • 2017-04-07 22:56
  • 2473

最小(代价)生成树

一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。 一.普利姆算法 从图中任意取出一个顶点,把他当作一棵树,然后从这棵树相接的边中选取一条最...
  • weixin_37720172
  • weixin_37720172
  • 2017-05-07 21:13
  • 664

最小代价生成树

#include using namespace std; const int Max = 100; int p[Max][Max]; const int maxCost = 99; int lowcost[Max]; int nearest[Max]; bool mark[Max]; void P...
  • u014338577
  • u014338577
  • 2015-08-17 18:15
  • 1259

动态规划算法,最小代价

int tempType;                 int cost = 0;      &...
  • shen332401890
  • shen332401890
  • 2015-06-22 16:19
  • 1913

动态规划--最小调整代价

91. Minimum Adjustment Cost 【题目】 Given an integer array, adjust each integers so that the difference of every adjacent integers are not greater than...
  • sinat_26230689
  • sinat_26230689
  • 2016-07-10 22:12
  • 2168

华为校招第三题:字符串变换最小费用(动态规划DP问题)

题目: 给出两个字串A,B。将A字串转化为B字串,转化一共有两种方式:删除连续的n个字符,一次操作费用为2。增加连续的n个字符(增加的字符是什么由你决定),一次操作费用为n+2。求把A变为B最小费用。输入: 第一行输入一个正整数T(1 <= T <= 10),表示有T组测试数据。 对...
  • wuxizhi777
  • wuxizhi777
  • 2016-09-04 15:21
  • 2838

动态规划系列问题-最小编辑代价

最小编辑代价(最小编辑距离) 题目描述: 给定两个字符串str1和str2,再给定三个整数ic,dc,rc,分别代表插入、删除、替换一个字符的代价,返回将str1编辑成str2的最小代价。 举例: str1="abc"   str2=&quo...
  • u013328850
  • u013328850
  • 2016-11-16 16:22
  • 381

java实现两点最小代价路线方案

由起点遍历最近点,再把该最近点看作一个新的起点去计算到终点的最小代价,以此类推通过迭代算出,最后返回最优方案和总代价。 点与点之间的代价也就是连线由数组来描述 如:distance[0][3]=1表示0点到3点距离为1 代码: import java.util.Scanner...
  • tangouyang
  • tangouyang
  • 2015-04-08 22:26
  • 311
    座右铭
    “要坚持梦想,要坚持梦想,要坚持梦想”重要的事情说三遍。没有谁生来就是神牛,而千里之行,始于足下!
    个人资料
    • 访问:98448次
    • 积分:3099
    • 等级:
    • 排名:第13284名
    • 原创:211篇
    • 转载:15篇
    • 译文:0篇
    • 评论:20条
    博客专栏
    最新评论