您的位置:首页 > 其它

CodeForces 125E MST Company(最小度限制生成树)

2017-09-04 22:02 585 查看
题意就不说了。

然后求最小度限制生成树的思路网上有很多。

下面是根据思路自己写的一个。

#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;
typedef long long LL;
const int MAXN = 5000+5;
const int inf = 1e9;
int n,m,k;
int ans;//最小k度限制生成树的总权值和
int p_min[MAXN],p[MAXN];//记录连接联通分量的最小权值、以及点
int mdu;//记录最小m度限制生成树的m
struct edge
{
int u,v,w;
int id;
bool operator < (const edge &a)const
{
return w < a.w;
}
} edge[100005],dp[MAXN];
int tu[MAXN][MAXN];//记录权值
bool link[MAXN][MAXN];//记录是否连接

int pre[MAXN];
int findx(int x)
{
return pre[x] == x?x : pre[x] = findx(pre[x]);
}

void kruskal()
{
for(int i = 1; i <= n; ++i)pre[i] = i;
for(int i = 0; i < m; ++i)
{
int u = edge[i].u;
int v = edge[i].v;
int w = edge[i].w;
if(u == 1 || v == 1)continue;
int fu = findx(u);
int fv = findx(v);
if(fu != fv)
{
pre[fv] = fu;
link[u][v] = link[v][u] = 1;
ans += w;
}
}
}
//求最小m度限制生成树
void solve1()
{
fill(p_min+1,p_min+1+n,inf);
for(int i = 2; i <= n; ++i)if(tu[1][i] != -1)
{
int fa = findx(i);
if(tu[1][i] < p_min[fa])
{
p_min[fa] = tu[1][i];
p[fa] = i;
}
}
for(int i = 1; i <= n; ++i)if(p_min[i] != inf)
{
mdu++;
link[1][p[i]] = link[p[i]][1] = 1;
ans += p_min[i];
}
}
//计算从1到某点路径中权值最大的边,且和1没有关系
void dfs(int u,int fa)
{
for(int v = 2; v <= n; ++v)
{
if(!link[u][v] || v == fa)continue;//没有边
if(dp[v].w  != -inf)//可以更新
{
if(tu[u][v] < dp[u].w)dp[v] = dp[u];
else dp[v].u = u,dp[v].v = v,dp[v].w = tu[u][v];
}
dfs(v,u);
}
}
//计算最小k度限制生成树
void solve2()
{
for(int i = mdu+1; i <= k; ++i)
{
for(int j = 1; j <= n; ++j)dp[j].w = -1;
dp[1].w = -inf;
for(int j = 1; j <= n; ++j)if(link[1][j])dp[j].w = -inf;//-inf表示搜不到它
dfs(1,0);
int key = 0,minn = inf;
for(int j = 2; j <= n; ++j)
if(tu[1][j] != -1 && tu[1][j] - dp[j].w < minn)
{
minn = tu[1][j] - dp[j].w;
key = j;
}
int u = dp[key].u;
int v = dp[key].v;
link[u][v] = link[v][u] = 0;
link[1][key] = link[key][1] = 1;
ans += minn;
}
}
bool check_tree()
{
int cnt = 0;
if(cnt == n-1)return 1;
sort(edge,edge+m);
for(int i = 1; i <= n; ++i)pre[i] = i;
for(int i = 0; i < m; ++i)
{
int u = edge[i].u;
int v = edge[i].v;
u = findx(u);
v = findx(v);
if(u != v)
{
pre[v] = u;
cnt++;
if(cnt == n-1)return 1;
}
}
return 0;
}

int ans_edge[MAXN];
int ans_cnt;
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i = 1; i <= n; ++i)
for(int j = i+1; j <= n; ++j)tu[i][j] = tu[j][i] = -1;
int tot = 0;
for(int i = 0; i < m; ++i)
{
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
edge[i].id = i+1;
if(edge[i].u == 1 || edge[i].v == 1)tot++;
tu[edge[i].u][edge[i].v] = tu[edge[i].v][edge[i].u] = edge[i].w;
}
if(tot < k || (n > 1&& k == 0))return 0*puts("-1");
if(!check_tree())return 0*puts("-1");

kruskal();
solve1();
//printf("%d %d\n",mdu,ans);
solve2();
ans_cnt = 0;
for(int i = 0; i < m; ++i)
{
int u = edge[i].u;
int v = edge[i].v;
if(link[u][v])ans_edge[ans_cnt++] = edge[i].id;
}
printf("%d\n",ans_cnt);
for(int i = 0; i < ans_cnt; ++i)printf("%d ",ans_edge[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: