2015百度之星 初赛2 连接的管道 最小生成树

来源:互联网 发布:c语言windows代码 编辑:程序博客网 时间:2024/04/30 03:54
题意:老 Jack 有一片农田,以往几年都是靠天吃饭的。但是今年老天格外的不开眼,大旱。所以老 Jack 决定用管道将他的所有相邻的农田全部都串联起来,这样他就可以从远处引水过来进行灌溉了。当老 Jack 买完所有铺设在每块农田内部的管道的时候,老 Jack 遇到了新的难题,因为每一块农田的地势高度都不同,所以要想将两块农田的管道链接,老 Jack 就需要额外再购进跟这两块农田高度差相等长度的管道。

现在给出老 Jack农田的数据,你需要告诉老 Jack 在保证所有农田全部可连通灌溉的情况下,最少还需要再购进多长的管道。另外,每块农田都是方形等大的,一块农田只能跟它上下左右四块相邻的农田相连通。

思路: 建图,边权值是两点高度之差的绝对值。最小生成树,跑一发克鲁斯卡尔就行了。这题容易爆内存...建图的时候可以只加入单向边以节省空间。


#include <iostream>#include <cstdio>#include <cmath>#include <cstdio>#include <vector>#include <queue>#include <algorithm>#include <cstring>#include <string>#include <cstdlib>#include <map>using namespace std;#define I64_MAX 9223372036854775807 typedef long long ll;const double pi=acos (-1.0);const double eps=1e-8 ;//const ll INF=(I64_MAX)/2;//#pragma comment(linker, "/STACK:102400000,102400000")const int inf=0x3f3f3f3f ;#define maxx(a) memset(a, 0x3f, sizeof(a))#define zero(a) memset(a, 0, sizeof(a))#define FILL(a,b) memset(a, b, sizeof(a))#define REP(i,a,b) for(i=a;i<b;i++)#define rep(i,n) REP(i,0,n)#define srep(i,n) for(i = 1;i <= n;i ++)#define snuke(c,itr) for( __typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)#define mp make_pair#define fi first#define se secondtypedef pair <int, int> pii;typedef pair <ll, ll> PX;typedef pair<int,ll> PIL;const int MAXN=1000006;//最大点数const int MAXM=2000006;//最大边数int F[MAXN];//并查集使用struct Edge{int u,v,w;}edge[MAXM];//存储边的信息,包括起点/终点/权值int tol;//边数,加边前赋值为0void addedge(int u,int v,int w){edge[tol].u=u;edge[tol].v=v;edge[tol++].w=w;}bool cmp(Edge a,Edge b){//排序函数,讲边按照权值从小到大排序return a.w<b.w;}int find(int x){if(F[x]==-1)return x;else return F[x]=find(F[x]);}int Kruskal(int n)//传入点数,返回最小生成树的权值,如果不连通返回-1{memset(F,-1,sizeof(F));sort(edge,edge+tol,cmp);int cnt=0;//计算加入的边数int ans=0;for(int i=0;i<tol;i++){int u=edge[i].u;int v=edge[i].v;int w=edge[i].w;int t1=find(u);int t2=find(v);if(t1!=t2){ans+=w;F[t1]=t2;cnt++;}if(cnt==n-1)break;}if(cnt<n-1)return -1;//不连通else return ans;}const int maxn = 1005;int mark[2][maxn];pii d[2];int n,m;inline int cal(int x,int y){return x*m+y;}int main(){int T;scanf("%d",&T);d[0] = mp(0,-1);d[1] = mp(-1,0);for(int t=1;t<=T;t++){scanf("%d%d",&n,&m);tol = 0;for(int i=0;i<n;i++){for(int j=0;j<m;j++){scanf("%d",&mark[i%2][j]);for(int k=0;k<2;k++){int x = i+d[k].fi;int y = j+d[k].se;if(x < 0 || y<0){continue;}int v = abs(mark[i%2][j] - mark[x%2][y]);//printf("%d %d\n",mark[i%2][j],mark[x%2][y]);int u1,u2;u1 = cal(i,j);u2 = cal(x,y); addedge(u1,u2,v);//addedge(u2,u1,v);//printf("u1=%d u2=%d v=%d\n",u1,u2,v);}}}printf("Case #%d:\n%d\n",t,Kruskal(n*m));}return 0;} 




0 0