[条件转换] 两两之间有且只有一条简单路径<==>树
题意:一个图中有两种边,求一棵生成树,使得这棵树中的两种边数量相等。
思路:
可以证明,当边的权是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: ...(最小生成树)