T1-------掌握魔法の东东
问题描述
东东在老家农村无聊,想种田。农田有 n 块,编号从 1~n。种田要灌氵
众所周知东东是一个魔法师,他可以消耗一定的 MP 在一块田上施展魔法,使得黄河之水天上来。他也可以消耗一定的 MP 在两块田的渠上建立传送门,使得这块田引用那块有水的田的水。 (1<=n<=3e2)
黄河之水天上来的消耗是 Wi,i 是农田编号 (1<=Wi<=1e5)
建立传送门的消耗是 Pij,i、j 是农田编号 (1<= Pij <=1e5, Pij = Pji, Pii =0)
东东为所有的田灌氵的最小消耗
Input
第1行:一个数n
第2行到第n+1行:数wi
第n+2行到第2n+1行:矩阵即pij矩阵
Output
东东最小消耗的MP值
Sample Input
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
Sample Output
9
解题思路以及关键代码
首先分析 如果没有把“黄河之水天上来”删掉,那么就是一个最小生成树问题。这个是我们熟悉的。
再者,考虑图重构:加一个超级源点 0 号,并向 n 个点连边为 Wi
,然后对这n+1 个点跑最小生成树即可。
全部代码
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = 3e2+5;
//图
struct Edge
{
int u,v,w;
bool operator < (const Edge& p) const
{
return w < p.w;
}
} edge[maxn*maxn];
int tot;
//并查集
int parent[maxn];
void initialize(int n)
{
for(int i=0;i<=n;i++)
parent[i]=i;
}
int find(int x)
{
if(parent[x]==x)
return x;
return parent[x] = find(parent[x]);
}
bool unite(int x,int y)
{
x = find(x) , y = find(y);
if(x==y)
return false;
parent[x] = y;
return true;
}
int kruskal(int n)
{
initialize(n);
sort(edge,edge+tot);
int cnt=0,ans=0;
for(int i=0;i<tot;i++)
{
if(unite(edge[i].u,edge[i].v))
{
ans+=edge[i].w;
cnt++;
if(cnt==n) //n+1个点求MST
return ans;
}
}
return -1;
}
int main()
{
tot = 0;
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&edge[tot].w);
edge[tot].u = 0;
edge[tot].v = i;
tot++;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&edge[tot].w);
if(i>=j)
continue;
edge[tot].u = i;
edge[tot].v = j;
tot++;
}
printf("%d",kruskal(n));
return 0;
}
T2-------csp数据中心
问题描述
Sample Input
4
5
1
1 2 3
1 3 4
1 4 5
2 3 8
3 4 2
Sample Output
4
解题思路以及关键代码
本题主要是题干过于复杂,给人一种读几遍读不懂到底在考什么的感觉。
但是仔细分析后可以得知,就是有权无向图,求解最优树解。
至于本题所指的最优树就是
给定无向图,求解一颗生成树,使得最大边权最小!
最大边权最小 就是 瓶颈生成树。而最小生成树一定是瓶颈生成树。
即转化为 求MST并且输出最大边。
全部代码
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = 5e4+5;
//图
struct Edge
{
int u,v,w;
bool operator < (const Edge& p) const
{
return w < p.w;
}
} edge[maxn*2];
int tot;
//并查集
int parent[maxn];
void initialize(int n)
{
for(int i=1;i<=n;i++)
parent[i]=i;
}
int find(int x)
{
if(parent[x]==x)
return x;
return parent[x] = find(parent[x]);
}
bool unite(int x,int y)
{
x = find(x) , y = find(y);
if(x==y)
return false;
parent[x] = y;
return true;
}
int kruskal(int n)
{
initialize(n);
sort(edge,edge+tot);
int cnt=0,ans=0;
for(int i=0;i<tot;i++)
{
if(unite(edge[i].u,edge[i].v))
{
ans=max(ans,edge[i].w);
cnt++;
if(cnt==n-1) //n个点求MST
return ans;
}
}
return -1;
}
int main()
{
tot = 0;
int n,m,root;scanf("%d%d%d",&n,&m,&root);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&edge[tot].u,&edge[tot].v,&edge[tot].w);
tot++;
}
printf("%d",kruskal(n));
return 0;
}