CodeForces 141E: ...(最小生成树)

[条件转换] 两两之间有且只有一条简单路径<==>树

题意:一个图中有两种边,求一棵生成树,使得这棵树中的两种边数量相等。

思路:

可以证明,当边的权是0或1时,可以生成最小生成树到最大生成树之间的任意值的生成树。

那么,方法就是生成最小生成树,然后,尽量替换0边,使得其成为值为(n-1)/2的生成树。

代码:

写的很乱,没有条理。还是应当先写出流程伪码后再敲代码的。


#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
#define PB push_back
#define N 1020
struct Edge{
int to;
int cost;
int id;
Edge(int a = 0, int b = 0, int c = 0): to(a), cost(b), id(c){};
};
vector<Edge> e[N];

int n, m;

int dis[N];
int vis[N];
struct Node{
int cost;
int id;
int edgeid;
Node(int a=0, int b=0, int c=0):cost(a),id(b),edgeid(c){}
bool operator < (const Node &b) const {
return cost > b.cost;
}
};
priority_queue<Node> que;

int prim() {
while(!que.empty()) que.pop();
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[1] = 0;
que.push(Node(0,1,0));
int sum = 0;
while (!que.empty()) {
int nowcost = que.top().cost;
int nowid = que.top().id;
int nowedgeid = que.top().edgeid;
que.pop();
if (vis[nowid]) continue;

//printf("(%d) ", nowedgeid);
sum += nowcost;
vis[nowid] = true;

for (int i = 0; i < e[nowid].size(); i++) {
int to = e[nowid][i].to;
int cost = e[nowid][i].cost;
if (vis[to]) continue;
if (dis[to] > cost) {
dis[to] = cost;
que.push(Node(cost, to, e[nowid][i].id));
}
}
}
return sum;
}

void solveprim(int changetime) {
//printf("changetime = %d\n", changetime);
vector<int> edgeids;
while(!que.empty()) que.pop();
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[1] = 0;
que.push(Node(0,1,0));
int sum = 0;
while (!que.empty()) {
int nowcost = que.top().cost;
int nowid = que.top().id;
int nowedgeid = que.top().edgeid;
que.pop();
if (vis[nowid]) continue;

if (nowedgeid != 0) {
if (changetime > 0 && nowcost == 0) {
bool change = false;
for (int i = 0; i < e[nowid].size(); i++) {
int to = e[nowid][i].to;
int cost = e[nowid][i].cost;
if (vis[to] && cost == 1) {
changetime--;
//printf("change! %d\n", e[nowid][i].id);
edgeids.push_back(e[nowid][i].id);
change = true;
break;
}
}
if (!change) {
edgeids.push_back(nowedgeid);
}
} else {
edgeids.push_back(nowedgeid);
}
}
sum += nowcost;
vis[nowid] = true;

for (int i = 0; i < e[nowid].size(); i++) {
int to = e[nowid][i].to;
int cost = e[nowid][i].cost;
if (vis[to]) continue;
if (dis[to] > cost) {
dis[to] = cost;
que.push(Node(cost, to, e[nowid][i].id));
}
}
}

if (changetime != 0) puts("-1");
else {
printf("%d\n", edgeids.size());
for (int i = 0; i < edgeids.size(); i++) {
printf("%d ", edgeids[i]);
}puts("");
}
return ;
}

int main() {
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 0; i <= n; i++) {
e[i].clear();
}
for (int i = 1; i <= m; i++) {
int u, v;
char type[20];
scanf("%d%d%s", &u, &v, type);
if (u == v) continue;
e[u].PB(Edge(v, type[0] == ‘S‘, i));
e[v].PB(Edge(u, type[0] == ‘S‘, i));
}
if (n%2 == 0) {
printf("-1\n");
continue;
}
int minsum = prim();
int should = (n-1)/2;
//printf("minsum = %d\n", minsum);
if (minsum <= should) {
solveprim(should-minsum);
} else {
printf("-1\n");
continue;
}
}
return 0;
}

CodeForces 141E: ...(最小生成树)

时间: 2024-10-24 22:39:41

CodeForces 141E: ...(最小生成树)的相关文章

正睿OI国庆DAY2:图论专题

正睿OI国庆DAY2:图论专题 dfs/例题 判断无向图之间是否存在至少三条点不相交的简单路径 一个想法是最大流(后来说可以做,但是是多项式时间做法 旁边GavinZheng神仙在谈最小生成树 陈主力说做法是dfs 首先两个点一定在点双联通分量里 点双是简单环,只有两条,不存在 猜测其他情况存在三条 双联通分量分解 输出情况可以用dfs树判,讨论非树边覆盖情况 内包含 下面分叉连到上面 相交 输出点即可 BFS/例题 BFS树没有跳跃边 计数/动态规划有用吧 树上bfs序好像可以判断距离? 边权

CodeForces 76A Gift - 最小生成树

The kingdom of Olympia consists of N cities and M bidirectional roads. Each road connects exactly two cities and two cities can be connected with more than one road. Also it possible that some roads connect city with itself making a loop. All roads a

Codeforces Gym 100203H Highways 最小生成树

原题链接:http://codeforces.com/gym/100203/attachments/download/1702/statements.pdf 题解 给你平面上若干点,生成一颗完全图,让你生成一颗最小生成树.模板题.图中已经有了的边要将权值置0.代码是队友写的. 代码 #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <

【最小生成树】Codeforces 707B Bakery

题目链接: http://codeforces.com/problemset/problem/707/B 题目大意: 给你N个点M条无向边,其中有K个面粉站,现在一个人要在不是面粉站的点上开店,问到面粉站的最短距离是多少.无法开店输出-1. 题目思路: [最小生成树] 把边长按距离从小到大排序,出现的第一个只含一个面粉店的边为所求. 1 // 2 //by coolxxx 3 //#include<bits/stdc++.h> 4 #include<iostream> 5 #inc

Make It Connected CodeForces - 1095F (建图+最小生成树)

Make It Connected CodeForces - 1095F You are given an undirected graph consisting of nn vertices. A number is written on each vertex; the number on vertex ii is aiai. Initially there are no edges in the graph. You may add some edges to this graph, bu

(最小生成树)Codeforces Educational Codeforces Round 9 Magic Matrix

You're given a matrix A of size n?×?n. Let's call the matrix with nonnegative elements magic if it is symmetric (so aij?=?aji), aii?=?0 and aij?≤?max(aik,?ajk) for all triples i,?j,?k. Note that i,?j,?k do not need to be distinct. Determine if the ma

(最小生成树)Codeforces 76 A Gift

The kingdom of Olympia consists of N cities and M bidirectional roads. Each road connects exactly two cities and two cities can be connected with more than one road. Also it possible that some roads connect city with itself making a loop. All roads a

Codeforces Round #303 (Div. 2) E. Paths and Trees (最短路+变形最小生成树)

题目地址:E. Paths and Trees 模拟了一场CF,这场实在太水了..边玩边做的..最后半分钟交了一发E题..不幸AK绝杀失败.... 首先的思路肯定是先求最短路,把可能为最短路的边挑出来,然后第二步我本来写的是直接用无向图的最小生成树,于是绝杀失败...后来才发现这样是不行的..因为边是有向边,而且每个点的入度要保证只有一个才行.于是我就把最小生成树的边弄成有向边,然后判定一下每个点的入度保证为1.然后就过了.. 代码如下: #include <iostream> #includ

【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集

[题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1<=wi<=10^9. [算法]最小生成树+倍增LCA+并查集 [题解]首先求出图的一个最小生成树,则所有边分成树边和非树边. 对于非树边(u,v),假设u和v在最小生成树上的路径的最大边权Max,那么一定满足w(u,v)<=Max /////////////////////////////////////// 原文地址:https://ww