题意:该题的题意晦涩,勉勉强强听别人说了一遍后再读了一遍题才算懂了题意,题图说的是A国因为B国药进攻自己的国家,于是想办法在联通A-B之间的路径上进行阻击。阻击的舰船停留在一个路径上,舰船上都要放置水晶,相同水晶的舰船可能会被一次性摧毁,于是现在要求给出尽可能多的方案来部署舰船,使得同一水晶的舰船能够阻断所有从B到A的路径,每条路径上只能够部署一部舰船。
分析:题意抽象之后就是一个网络求出从源点到汇点的尽可能多的割边集,且每个割边集没有公共边。根据题目的要求,我们设想从A到B的最短路长度为K,那么假设方案数大于K,那么每个割边集至少要包含该最短路上的一条边,否则存在从A到B的通路,那么这个包含的最优方法是一次包含一条,即便如此该过程也只能够进行K次,超过K次后必定不能够再包含最短路上的任何一条边,因此最后的答案就是K了,然后输出求出最短路之后的距离为1的边集即可。
#include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> using namespace std; const int N = 405; int n, m, s, t; int dis[N]; char vis[N], mp[N][N]; queue<int>q; vector<int>v[N]; struct Edge { int a, b; }e[N*N]; void spfa() { memset(dis, 0x3f, sizeof (dis)); memset(vis, 0, sizeof (vis)); dis[s] = 0, vis[s] = 1; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for (int v = 1; v <= n; ++v) { if (!mp[u][v]) continue; if (dis[v] > dis[u] + 1) { dis[v] = dis[u] + 1; if (!vis[v]) { vis[v] = 1; q.push(v); } } } } } int main() { int T; scanf("%d", &T); while (T--) { memset(mp, 0, sizeof (mp)); scanf("%d %d %d %d", &n, &m, &s, &t); int a, b; for (int i = 0; i < n; ++i) v[i].clear(); for (int i = 1; i <= m; ++i) { scanf("%d %d", &a, &b); mp[a][b] = mp[b][a] = 1; e[i].a = a, e[i].b = b; } spfa(); printf("%d\n", dis[t]); for (int i = 1; i <= m; ++i) { int a = e[i].a, b = e[i].b; if (dis[a]+1==dis[b]) { v[dis[a]].push_back(i); } else if (dis[b]+1==dis[a]) { v[dis[b]].push_back(i); } } for (int i = 0; i < dis[t]; ++i) { printf("%d", v[i].size()); for (int j = 0; j < v[i].size(); ++j) { printf(" %d", v[i][j]); } puts(""); } } return 0; }