时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
有一个连通图 包含 n 个点 n 条无向边 其中每个点都与其他的两个点直接相连 (即这是一个环)
现在这个环的边变成了有向边 变成了有向边后得到的有向图不一定是强连通的
(强连通图是指一个有向图中任意两点v1、v2间存在v1到v2的路径及v2到v1的路径的图)
所以现在给出 n 条有向边和把某条有向边转换方向后的代价, 问要使输入的有向图变成一个强连通图
例如输入
3
1 3 1
1 2 1
3 2 1
表示有一条有向边 1 -> 3 如果把这条边变成 3 -> 1 的代价是 1
表示有一条有向边 1 -> 2 如果把这条边变成 2 -> 1 的代价是 1
表示有一条有向边 3 -> 2 如果把这条边变成 2 -> 3 的代价是 1
对于输入的这个有向图是不存在 2 -> 3 的路径的 所以可以把 有向边 1 -> 2 变为 2 -> 1 这样图中任意两点均相互可达
输入描述:
多组测试数据。 第一行给出数字n,代表顶点数量 (3 ≤ n ≤ 100)。 接下来n行给出路径。 每行给出三个数字ai, bi, ci (1 ≤ ai, bi ≤ n, ai ≠ bi, 1 ≤ ci ≤ 100) — 代表ai指向bi。代价是ci。
输出描述:
输出最小代价
示例1
输入
3 1 3 1 1 2 1 3 2 1 3 1 3 1 1 2 5 3 2 1 6 1 5 4 5 3 8 2 4 15 1 6 16 2 3 23 4 6 42
输出
1 2 39
思路:每一个点都和其他两个点相连,易看出这些点必然组成一个环。题目让求的就是把这个环变成顺时针所需要的代价小,还是变成逆时针所需要的代价小。
首先,利用dfs还原这个环,给环中每一个点按环中的顺序编上号。然后顺时针、逆时针枚举,看那个所需代价小即可。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=110;
int n;
int a[N][N];
int snum[N],s;//snum存储环中每个点的序号
bool vis[N];
void dfs(int u)
{
vis[u]=1;
snum[s++]=u;
for(int i=1;i<=n;i++)
{
if(!vis[i]&&(a[i][u]||a[u][i]))
dfs(i);
}
}
int main()
{
// freopen("input.txt","r",stdin);
while(cin>>n)
{
s=0;
memset(a,0,sizeof a);
memset(snum,0,sizeof snum);
memset(vis,0,sizeof vis);
for(int i=0;i<n;i++)
{
int x,y,e;
cin>>x>>y>>e;
a[x][y]=e;
}
dfs(1);
snum[s]=1;
int ans1=0,ans2=0;
for(int i=0;i<n;i++) ans1+=a[snum[i]][snum[i+1]];
for(int i=n;i>=1;i--) ans2+=a[snum[i]][snum[i-1]];
cout<<min(ans1,ans2)<<endl;
}
return 0;
}