[条件转换] 两两之间有且只有一条简单路径<==>树
题意:一个图中有两种边,求一棵生成树,使得这棵树中的两种边数量相等。
思路:
可以证明,当边的权是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 ", 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 ", 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 ", 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 "); continue; } int minsum = prim(); int should = (n-1)/2; //printf("minsum = %d ", minsum); if (minsum <= should) { solveprim(should-minsum); } else { printf("-1 "); continue; } } return 0; }