您的位置:首页 > 其它

度限制最小生成树 POJ 1639 贪心+DFS+prim

2013-08-10 16:38 453 查看
很好的解题报告:

http://blog.csdn.net/new_c_yuer/article/details/6365689

注意两点:

1.预处理环中权值最大的边····

2.可以把去掉度限制后的点看成是连通的,权值为无穷远的点也看做是连通的,反正后面肯定会替换出来的····

我的代码没有预处理出权值最大的边,但是第2点事做到了的,这样便于代码的实现·····

贴代码:

#include <cstdio>
#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#define INF 0x3f3f3f3f
#define N 505
using namespace std;
map<string,int> ma;
map<string,int>::iterator it;
int n,k;//点的个数,度数限制
bool flag;
long long int ans;//最后的结果
bool in

,vis
;//加入最小生成树中的边
int edge

,pre
, next
,lowcost
;//边,确定哪些边被加入了最小生成树中,存环中的边,求最小生成树
int Find(char c[])
{
it = ma.find(c);
if(it != ma.end())
return it->second;
ma[c] = ++n;
return n;
}
//用prim函数求一次去掉度限制的点后的最小生成树
void prim()
{
lowcost[1] = -1;
for(int i=2; i<=n; ++i)
{
lowcost[i] = edge[1][i];
pre[i] = 1;
}
for(int i=2; i<=n; ++i)
{
int v;
int minum=INF;
for(int j=2; j<=n; ++j)
{
if(lowcost[j] != -1 && minum >= lowcost[j])
{
minum = lowcost[j];
v = j;
}
}
lowcost[v] = -1;
ans += edge[v][pre[v]];
in[v][pre[v]] = in[pre[v]][v] = 1;
for(int j=2; j<=n; ++j)
{
if(lowcost[j] != -1 &&  lowcost[j] > edge[j][v] )
{
lowcost[j] = edge[j][v];
pre[j] = v;
}
}
}
}
//dfs找出环
void dfs(int x)
{
if(x == 0)
{
flag = true;
return;
}
vis[x] = 1;
for(int i = n; i >= 0; --i)
{
if(in[x][i] && !vis[i] && !flag)
{
next[x] = i;
dfs(i);
}
}
}
//找环上权值最大的边
void findMax(int x,int &s,int &e,int &maxnum)
{
memset(vis,0,sizeof(vis));
flag = false;
dfs(x);
maxnum = edge[0][x];
int ne = x;
while(next[ne] != 0)
{
if(edge[ne][next[ne]] > maxnum)
{
maxnum = edge[ne][next[ne]];
s = ne;
e = next[ne];
}
ne  = next[ne];
}
}
//找度限制为k的最小生成树
void kTree()
{
int minum = INF;
int v;
for(int i=1; i<=n; ++i)
{
if(edge[0][i] < minum)
{
minum = edge[0][i];
v =  i;
}
}
in[v][0] = in[0][v] = 1;
ans += edge[0][v];
for(int t=1; t<k; ++t)
{
minum = INF;
v = -1;
int s,e,m;
for(int i=1; i<=n; ++i)
{
if(!in[0][i] && edge[0][i] < INF)
{
int ss,ee,maxnum;
findMax(i,ss,ee,maxnum);
if(edge[0][i] - maxnum < minum)
{
minum = edge[0][i] - maxnum ;
s = ss;
e = ee;
m = minum;
v= i;
}
}
}
if(v == -1) break;
if(minum >= 0 ) break;
in[0][v] = 1;
in[v][0] = 1;
in[s][e] = 0;
in[e][s] =0;
ans += minum;
}
printf("Total miles driven: %d\n",ans);
}
// 初始化输入
void initScan()
{
int m;
ma["Park"] = n;
scanf("%d",&m);
memset(edge,0x3f,sizeof(edge));
for(int i=0; i<m; ++i)
{
char a1
,a2
;
int u,v,w;
scanf("%s %s %d",a1,a2,&w);
u = Find(a1);
v = Find(a2);
edge[u][v] = w;
edge[v][u] = edge[u][v];
}
scanf("%d",&k);
}
int main()
{
initScan();
prim();
kTree();
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: