测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M (N, M < =100 );随后的 N 行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
3 3 1 2 1 1 3 2 2 3 4 1 3 2 3 2 0 100
3 ?
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 105;
struct node {
int a,b;
int len;
bool operator<(node x) {
return len < x.len;
}
}road[MAXN];
int tab[MAXN]; //并查集表
int father(int x) {
return (x == tab[x]) ? x : father(tab[x]);
}
void Union(int a, int b) {
tab[father(b)] = father(a);
}
bool CheckLink(int m) { //检查是否为多连通图,若有一节点的根与众不同,则为多连通图
int f = father(1);
for (int i = 2; i <= m; i++) {
if (f != father(i))
return false;
}
return true;
}
int main() {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
if (!n) break;
for (int i = 1; i <= m; i++) //并查集初始化
tab[i] = i;
int ans = 0;
for (int i = 1; i <= n; i++) { //所有下标从1开始
scanf("%d%d%d", &road[i].a,
&road[i].b, &road[i].len);
}
sort(road + 1, road + 1 + n); //排序后即为kruskal算法的思想,依大小顺序并入有效边
for (int i = 1; i <= n; i++) {
int a = road[i].a, b = road[i].b;
if (father(a) == father(b)) continue;
Union(a, b);
ans += road[i].len;
//cout << "road :" << road[i].a << " " << road[i].b << " " << road[i].len << endl;
}
if (CheckLink(m)) printf("%d\n", ans);
else printf("?\n");
}
return 0;
} #include<stdio.h>
#include<algorithm>
#define N 101
using namespace std;
int Tree[N];
typedef struct Edge{
int a,b;
int cost;
}Edge;
int FindRoot(int x){
if(Tree[x]==-1) return x;
else{
Tree[x]=FindRoot(Tree[x]);
return Tree[x];
}
}
bool cmp(Edge a,Edge b){
return a.cost<b.cost;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF&&n!=0){
int i;
Edge e[N];
for(i=1;i<=m;i++)
Tree[i]=-1;
for(i=0;i<n;i++)
scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].cost);
sort(e,e+n,cmp);
int a,b;
int ans=0;
for(i=0;i<n;i++){
a=FindRoot(e[i].a);
b=FindRoot(e[i].b);
if(a!=b){
Tree[b]=a;
ans+=e[i].cost;
}
}
int count=0;
for(i=1;i<=m;i++)
if(Tree[i]==-1)
count++;
if(count==1)
printf("%d\n",ans);
else
puts("?");
}
}
/*
*kruskal 最小生成树。并查集表征连通分量。
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4;
struct edge
{
int u, v, w;
edge(int _u=0,int _v=0,int _w=0):u(_u),v(_v),w(_w){}
};
vector<edge> edges;
int father[maxn+5];
int n, m;
bool cmp(edge a, edge b)
{
return a.w < b.w;
}
void Initial()
{
for(int i = 1;i <= n; i++) father[i] = i;
}
int getFather(int x)
{
int a = x;
while(x != father[x]) x = father[x];
//路径压缩
while(a != father[a])
{
int z = a; a = father[a]; father[z] = x;
}
return x;
}
void Create()
{
int u, v, w, f;
for(int i = 0;i < m; i++)
{
cin >> u >> v >> w;
edges.push_back(edge(u, v, w));
}
}
int Kruskal()
{
Initial();
sort(edges.begin(), edges.end(), cmp);
int ans = 0, num = 0;
for(int i = 0;i < edges.size(); i++)
{
int fu = getFather(edges[i].u);
int fv = getFather(edges[i].v);
if(fu != fv)
{
father[fu] = fv;
ans += edges[i].w; num++;
if(num == n-1) break;
}
}
if(num != n-1) return -1;
else return ans;
}
int main()
{
ios::sync_with_stdio(false);
while(cin >> m >> n && m)
{
Create();
int ans = Kruskal();
if(ans == -1) cout << "?" << '\n';
else cout << ans << '\n';
}
return 0;
}
// runtime: 4mm
// space: 432K
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 101;
struct Road {
int from;
int to;
int price;
bool operator< (const Road& r) const {
return price < r.price;
}
};
int father[MAX];
int height[MAX];
Road road[MAX];
void Initial(int n) { // 初始化
for (int i = 1; i <= n; ++i) {
father[i] = i;
height[i] = 0;
}
}
int Find(int x) { // 查找根结点
if (x != father[x]) { // 路径压缩
father[x] = Find(father[x]);
}
return father[x];
}
void Union(int a, int b) { // 合并
a = Find(a);
b = Find(b);
if (a != b) {
if (height[a] < height[b]) {
father[a] = b;
} else if (height[a] > height[b]) {
father[b] = a;
} else {
father[a] = b;
height[b]++;
}
}
}
int MinPrice(int roadNum, int villageNum) {
int answer = 0, part = 0;
sort(road, road + roadNum);
for (int i = 0; i < roadNum; ++i) {
Road current = road[i];
if (Find(current.from) != Find(current.to)) {
Union(current.from, current.to);
answer += current.price;
}
}
for (int j = 1; j <= villageNum; ++j) {
if (father[j] == j)
part++;
}
if (part != 1)
answer = -1;
return answer;
}
int main() {
int roadNum, villageNum;
while (cin >>roadNum) {
if (roadNum == 0)
break;
cin >> villageNum;
Initial(villageNum);
for (int i = 0; i < roadNum; ++i) {
cin >> road[i].from >> road[i].to >> road[i].price;
}
int answer = MinPrice(roadNum, villageNum);
if (answer == -1)
cout << "?" << endl;
else
cout << answer << endl;
}
return 0;
}
import java.util.Arrays;
import java.util.Scanner;
public class Main {
//并查集+Kruskal算法
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
if (n == 0) break;
int m = scanner.nextInt();
UnionFind unionFind = new UnionFind(m + 1);
Path[] paths = new Path[n];
for (int i = 0; i < n; i++) paths[i] = new Path(scanner.nextInt(), scanner.nextInt(), scanner.nextInt());
Arrays.sort(paths);
int sum = 0;
for (Path path : paths) {
if (unionFind.count > 2) {
if (unionFind.find(path.a)!=unionFind.find(path.b)){
unionFind.union(path.a, path.b);
sum += path.cost;
}
} else break;
}
System.out.println(unionFind.count==2?sum:"?");
}
}
public static class UnionFind {
private int[] id;
public int count;
public UnionFind(int N) {
count = N;
id = new int[N];
for (int i = 0; i < N; i++) id[i] = i;
}
public int find(int p) {
return id[p];
}
public void union(int p, int q) {
int pRoot = find(p);
int qRoot = find(q);
if (pRoot == qRoot) return;
for (int i = 0; i < id.length; i++)
if (id[i] == pRoot) id[i] = qRoot;
count--;
}
}
static class Path implements Comparable<Path> {
Integer a;
Integer b;
Integer cost;
public Path(Integer a, Integer b, Integer cost) {
this.a = a;
this.b = b;
this.cost = cost;
}
@Override
public int compareTo(Path o) {
return this.cost.compareTo(o.cost);
}
}
} #include<cstdio>
(802)#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=100;
struct Edge{
int from;
int to;
int len;
};
int father[MAXN];
int height[MAXN];
Edge e[MAXN*MAXN];
bool visit[MAXN]={false};
void initial(int n){
for(int i=0;i<=n;i++){
father[i]=i; //初始每个结点的父亲为自己
height[i]=0; //每个结点的高度初始为 0
}
}
int find(int x){ //查找根结点
if(x!=father[x]){ //根结点不为自己
father[x]=find(father[x]);//则回溯到根结点
}
return father[x];
}
void Union(int x,int y){
x=find(x); //x的根结点
y=find(y); //找到 y 的根结点
if(x!=y){ //x y 的根结点不一致
if(height[x]<height[y]){//矮树为高树的子树
father[x]=y; //将 x树的根结点设为y
}else if(height[x]>height[y]) father[y]=x;
else { //两树一样高
father[y]=x;
height[x]++;
}
}
return ;
}
bool cmp(Edge x,Edge y){
return x.len<y.len;
}
int kruskal(int m,int n){
int sum=0,num=0;
initial(m); //初始化
sort(e,e+n,cmp);
for(int i=0;i<n;i++){
Edge cur=e[i];
if(find(cur.from)!=find(cur.to)&&visit[cur.from]==false&&visit[cur.to]==false){
Union(cur.from,cur.to);//合并集合
visit[cur.from]==true;
visit[cur.to]==true;
sum+=cur.len;
}
}
for(int i=1;i<=m;i++){
if(i==find(i)) num++;
}
if(num==1) return sum;
else return -1;
}
int main(){
int n,m;//m个村庄,n条道路
while(scanf("%d",&n)!=EOF){
if(n==0) break;
scanf("%d",&m);
for(int i=0;i<n;i++){
scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].len);
}
int answer=kruskal(m,n);
if(answer!=-1) printf("%d\n",answer);
else printf("?\n");
}
return 0;
} 畅通工程系列我都是用并查集,kruskal算法来做的~代码长,但是套路简单
/*畅通工程*/只想问一下各位大佬,为什么我想着用DFS来遍历全部节点,得出每次的成本总和,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//自己回忆了下prim算法按感觉写的
//这道题实在想爆粗口,开始写觉得正确死活过不了,仔细查看样例,发现居然有 3 4 6,3 4 5 这样的毒数据,我真是***了,小改了一下过了
//望大家注意
int dis[105][105];
int Visited[105][105];
int visited[105];
int main(void){
int n,m,i,j,point,res,k,minDis,start,end,cnt,temp;
while(scanf("%d %d",&n,&m) != EOF){
if(n == 0) return 0;
memset(dis,0,sizeof(dis));
memset(visited,0,sizeof(visited));
memset(Visited,0,sizeof(Visited));
for(i = 0;i < n;i++){
scanf("%d %d",&j,&k);
if(Visited[j][k] == 0 ){ //两个节点之间的距离取最小的那一个
Visited[j][k] = Visited[k][j] = 1;
scanf("%d",&dis[j][k]);
dis[k][j] = dis[j][k];
}
else {
scanf("%d",&temp);
if(temp < dis[j][k]){
dis[j][k] = temp;
dis[k][j] = temp;
}
}
}
visited[1] = 1;
point = m - 1;
res = 0;
while(point){
minDis = 9999999;
for(i = 1; i <= m;i++){
if(visited[i] == 1){
for(j = 1;j <= m;j++){
if(visited[j] == 0 && dis[i][j] != 0){
if(dis[i][j] < minDis){
minDis = dis[i][j];
end = j;
}
}
}
}
}
visited[end] = 1;
res += minDis;
point--;
}
cnt = 0;
for(i = 1 ;i <= m ;i++){
if(visited[i] == 1) cnt++;
}
if(cnt == m) printf("%d\n",res);
else {
printf("?\n");
}
}
return 0;
}
#include<iostream>
#include<algorithm>
#include<limits.h>
using namespace std;
int matrix[101][101];
int dist[101];
int main(){
int i,j,n,m,x,y,cost;
while(cin>>n>>m){
if(n==0){break;}
else{
for(i=0;i<101;++i){
for(j=0;j<101;++j){
if(i==j){matrix[i][j]=0;}
else{matrix[i][j]=INT_MAX;}
}
}
for(i=0;i<n;++i){
cin>>x>>y>>cost;
if(matrix[x][y]>cost){matrix[x][y]=matrix[y][x]=cost;}//初始化
}
bool is_connect=true;
int count=0;
for(i=1;i<=m;++i){//判断是否连通
count=0;
for(j=1;j<=m;++j){
if(matrix[i][j]==INT_MAX){++count;}
}
if(count==m-1){is_connect=false;}//如果一个村除了到自己的距离都是INT_MAX,说明图不连通
}
if(is_connect==false){cout<<"?"<<endl;}
else{//prim方法构造最小生成树
int sum=0,count=1,min_dist,t;
for(i=1;i<=m;++i){dist[i]=matrix[1][i];}
while(count<m){
min_dist=INT_MAX;
for(i=1;i<=m;++i){
if(dist[i]<min_dist&&dist[i]!=0){min_dist=dist[i];t=i;}
}
dist[t]=0;
sum+=min_dist;
for(i=1;i<=m;++i){
if(matrix[t][i]<dist[i]){dist[i]=matrix[t][i];}
}
++count;
}
cout<<sum<<endl;
}
}
}
return 0;
}
#include<stdio.h>
#include<algorithm>
using namespace std;
int tree[110];
struct Edge{
int a,b;
int cost;
}buf[110];
bool cmp(Edge a,Edge b){
return a.cost<b.cost;
}
int sum[110];
int findroot(int x){
if(tree[x]==-1){
return x;
}
else {
int tmp=findroot(tree[x]);
tree[x]=tmp;
return tmp;
}
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
if(n==0){
break;
}
for(int i=1;i<=n;i++){
scanf("%d%d%d",&buf[i].a,&buf[i].b,&buf[i].cost);
}
sort(buf+1,buf+1+n,cmp);
for(int i=1;i<=m;i++){
tree[i]=-1;
sum[i]=1;
}
int ans=0;
for(int i=1;i<=n;i++){
int a=findroot(buf[i].a);
int b=findroot(buf[i].b);
if(a!=b){
tree[a]=b;
sum[b]=sum[a]+sum[b];
ans=ans+buf[i].cost;
}
}
int flag=0;
for(int i=1;i<=m;i++){
if(sum[i]==m){
flag=1;
break;
}
}
if(flag!=0){
printf("%d\n",ans);
}
else printf("?\n");
}
return 0;
}
def findRoot(village):
global villages
if villages[village] == -1:
return village
else:
temp = findRoot(villages[village])
villages[village] = temp
return temp
while True:
try:
n,m = list(map(int,input().split()))
if n == 0:
break
roads = []
for i in range(n):
roads.append(list(map(int,input().split())))
values = 0
villages = [-1 for i in range(m+1)]
nodeNum = 1
roads.sort(key=lambda x:x[2])
for i in range(n):
a = findRoot(roads[i][0])
b = findRoot(roads[i][1])
if a != b:
villages[a] = b
values += roads[i][2]
nodeNum += 1
if nodeNum == m:
break
if nodeNum == m:
print(values)
else:
print('?')
except Exception:
break
最小生成树
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Collections;
class Edge implements Comparable{
int begin;
int end;
int cost;
Edge next;
public Edge(int begin, int end, int cost){
this.begin = begin;
this.end = end;
this.cost = cost;
this.next = null;
}
@Override
public int compareTo(Object o){
Edge edge = (Edge) o;
return this.cost - edge.cost;
}
}
public class Main{
static int[] root;
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
while(scan.hasNext()){
int N = scan.nextInt();
int M = scan.nextInt();
root = new int[M+1];
for(int i=0;i<=M;i++)
root[i] = -1;
ArrayList<Edge> arr = new ArrayList<Edge>();
for(int i=0;i<N;i++){
Edge edge = new Edge(scan.nextInt(), scan.nextInt(), scan.nextInt());
arr.add(edge);
}
Collections.sort(arr);
int sum=0;
while(!arr.isEmpty()){
Edge tmp = arr.get(0);
int a = findRoot(tmp.begin);
int b = findRoot(tmp.end);
if(a==b) arr.remove(0);
else{
root[a] = b;
sum += tmp.cost;
}
}
int cnt=0;
for(int i=1;i<=M;i++)
if(root[i]==-1) cnt++;
if(cnt==1) System.out.println(sum);
else System.out.println("?");
}
}
public static int findRoot(int x){
if(root[x]==-1) return x;
int tmp = findRoot(root[x]);
root[x] = tmp;
return tmp;
}
}
#include <cstdio>
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
int father[10001];
void InitSet(int n) {
for (int i = 0; i < n; i++) {
father[i] = i;
}
}
int FindFather(int u) {
if (u == father[u]) {
return u;
} else {
father[u] = FindFather(father[u]);
return father[u];
}
}
void UnionSet(int r, int t) {
r = FindFather(r);
t = FindFather(t);
father[r] = t;
}
struct edge {
int u;//边的两个结点、权值
int v;
int w;
edge(int _u, int _v, int _w) {
u = _u;
v = _v;
w = _w;
}
};
bool cmp(edge a, edge b) {
return a.w < b.w;
}
int main() {
int n, m; //道路数、村庄数
while (scanf("%d%d", &n, &m) != EOF) {
vector<edge> edgev;//存储边的向量
if (0 == n) {
break;
}
if (n < m - 1) {
printf("?\n"); //如果道路总数已经村庄数那么必定不连通直接break
break;
}
for (int i = 0; i <n; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
edge e(u, v, w);
edgev.push_back(e);
}
InitSet(10001);
sort(edgev.begin(), edgev.end(), cmp);
int edgenum = 0, totaledgesum = 0; //边的数量与权值之和
for (int i = 0; i < edgev.size(); i++) {
int u = edgev[i].u, v = edgev[i].v, w = edgev[i].w;
if (FindFather(u) != FindFather(v)) {
edgenum++;
UnionSet(u, v);
totaledgesum += w;
}
if (edgenum == n - 1) { //最小树已经生成完毕
break;
}
}
if (edgenum < m - 1) {
printf("?\n"); //不连通
} else {
printf("%d\n", totaledgesum);
}
}
}
// 64 位输出请用 printf("%lld") #include<stdio.h>
#include<math.h>
#include<stdlib.h>
struct Point{
int x;
int y;
};
struct Edge{
int from;
int to;
int cost;
};
int father[101];
struct Edge edge[101];
int height[101];
void inital(int n){
for(int i = 1; i <= n; i++){
father[i] = i;
height[i] = 1;
}
}
int cmp(const void*a, const void*b ){
struct Edge* edgea = (struct Edge *) a;
struct Edge* edgeb = (struct Edge *) b;
if(edgea->cost < edgeb->cost) return -1;
else if(edgea->cost > edgeb->cost) return 1;
return 0;
}
int Find(int x) {
if (x != father[x])
father[x] = Find(father[x]);
return father[x];
}
void Union(int x, int y) {
x = Find(x);
y = Find(y);
if (x != y) {
if (height[x] > height[y])
father[y] = x;
else if (height[y] > height[x])
father[x] = y;
else {
father[y] = x;
height[x]++;
}
}
}
int kruskal(struct Edge edge[], int edgenum){
int ans = 0;
qsort(edge, edgenum, sizeof(struct Edge), cmp);
for(int i = 0; i < edgenum; i++){
if(Find(edge[i].from) != Find(edge[i].to)){
Union(edge[i].from, edge[i].to);
ans += edge[i].cost;
}
}
return ans;
}
int main(){
int n, m, a, b, c, res, x, y;
while(scanf("%d %d", &n, &m)!=EOF){
if (n == 0) break;
inital(m);
for(int i = 0; i < n; i++){
scanf("%d %d %d", &edge[i].from, &edge[i].to, &edge[i].cost);
}
res = kruskal(edge, n);
x = father[1];
int tag = 0;
for(int i = 2; i <= m; i++){
y = Find(i);
if (x != y) {
tag = 1;
break;
}
}
if(tag == 0)
printf("%d\n",res);
else
printf("%s\n", "?");
}
return 0;
}