Blue Book 上的图论T(未完成)
Sorting It All Out:
对于可以得到绝对顺序的图,拓扑排序可以直接确定顺序
如果拓扑排序没能遍历所有的点,就说明存在一个环。
set也可以用count,我为什么才知道
Sightseeing trip:(无向图的最小环问题):
考虑一个图中的最小环u->v->k->u,如果我们随意去掉其中一条边u->v
那么剩下的v->k->u一定是图中u->v建的最短路径
在Floyed算法枚举k的时候,已经得到了前k-1个点的最短路径,这k-1个点不包括k,并且他们的最短路径中也不包括k点
由对称性可知,这样做并不会影响结果
走廊泼水节;(https://www.acwing.com/problem/content/348/)
又是熟悉的感觉?有一个题是完全图最短路,开始边权相同,后来有修改,修改只涉及了最多6000个点,就把修改的拿出来
好像是多校里的某个T4->欢乐豆,这种取出某些点单独最短路的套路可以应用到[最短路问题V3]
为了保证(x, y)一定在最小生成树中,就必须让(x, y)是连接集合Sx与Sy的权值最小的边,因此(u, v)的权值应该定为w(x, y)+1
求增加的边的权值,从原有的边里找
Picnic Planning:(https://www.acwing.com/problem/content/349/)
书看了一半,以为拆出来连通块之后问题就完美解决,然后被后半部分吓到了
鹤完文字版就鹤code
没有作者的高级题意转化还真不容易想到最小生成树,关于映射也有一点细节
口胡很容易但是对鹤就不太友好。。
Star way to heven 好像也是一道用prim跑最小生成树的题,很少用prim还是很不熟练
忽然发现也不是必须用prim。。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1005;
const int inf = 0x7fffffff;
int n, tot, k, mpcnt;
map<string, int> mp;
const string park = "Park";
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct Build_graph
{
int mp[maxn][maxn]; bool link[maxn][maxn];
inline void _add(int u, int v, int w) {link[u][v] = link[v][u] = true; mp[u][v] = mp[v][u] = w;}
inline void _cut(int u, int v) {link[u][v] = link[v][u] = false; mp[u][v] = mp[v][u] = inf;}
inline void init(int n)
{
for(int i=1; i<=n; i++) for(int j=1; j<=n; j++)
{
link[i][j] = false; mp[i][j] = inf;
}
}
}Old;
struct Kruskal
{
struct edge
{
int a, b, v;
bool operator < (const edge &T) const
{
return v > T.v;
}
};
priority_queue<edge> q;
int v0, tree_num, ans;
int f[maxn], Minn_dis[maxn], Minn_id[maxn];
Kruskal():tree_num(0), ans(0){}
void addEdge(int x, int y, int v)
{
q.push({x, y, v});
}
int find(int x)
{
if(f[x] == x) return x;
return f[x] = find(f[x]);
}
void init(int n)
{
tree_num = 0; ans = 0;
for(int i=1; i<=n; i++)
{
f[i] = i; Minn_id[i] = i;
Minn_dis[i] = inf;
}
while(!q.empty()) q.pop();
}
int kruskal(int n)
{
int ret = 0;
while(!q.empty())
{
edge now = q.top(); q.pop();
int fa = find(now.a), fb = find(now.b);
if(now.a == v0)//这时fb一定要并到fa上,每一条边都算数
{
if(Minn_dis[fb] > now.v) {Minn_dis[fb] = now.v; Minn_id[fb] = now.b;}
}
else if(now.b == v0)
{
if(Minn_dis[fa] > now.v) {Minn_dis[fa] = now.v; Minn_id[fa] = now.a;}
}
else
{
if(fa != fb)
{
ret += now.v;
f[fa] = fb;
if(Minn_dis[fa] < Minn_dis[fb])
{
Minn_dis[fb] = Minn_dis[fa]; Minn_id[fb] = Minn_id[fa];
}
Old._add(now.a, now.b, now.v);
}
}
}
//先删掉v0,再从v0向每一个删掉它得到的连通块连一条边
for(int i=1; i<=n; i++)
{
if(i == v0) continue;
if(find(i) == i)
{
ret += Minn_dis[i];
tree_num++;
Old._add(v0, Minn_id[i], Minn_dis[i]);
}
}
ans = ret;
return ret;
}
}a;
struct K_limit_tree
{
struct DP
{
int id, fa, dis;
DP(int a=0, int c=0, int b=0):id(a), fa(c), dis(b){}
friend bool operator < (DP e1, DP e2) {return e1.dis < e2.dis;}
}dp[maxn];
struct V0 {int v, w;};
vector<V0> v0link;
int v0;
void dfs(int u, int fa, const int n)
{
for(int i=1; i<=n; i++)
{
if(i == v0) continue;
if(Old.link[u][i] && (i^fa))
{
//每个点到v0最短路径上的权值最大的边dp[i]
dp[i] = max(DP(i, u, Old.mp[u][i]), dp[u]);
dfs(i, u, n);
}
}
}
void solve(Kruskal &kru, int K, const int n)
{
v0 = kru.v0;
dfs(kru.v0, 0, n);
int len = v0link.size();
//本来应该从+1开始的,现在让K-1也是等效
for(int tims=kru.tree_num,maxx_det,id; tims<K; tims++)
{
maxx_det = -inf; id = -1;
for(int i=0; i<len; i++)
{
if(dp[v0link[i].v].dis-v0link[i].w > maxx_det && !Old.link[kru.v0][v0link[i].v])
{
maxx_det = dp[v0link[i].v].dis - v0link[i].w;
id = i;
}
}
if(maxx_det <= 0) break;
kru.ans -= maxx_det;
Old._add(kru.v0, v0link[id].v, v0link[id].w);
Old._cut(dp[v0link[id].v].id, dp[v0link[id].v].fa);
dfs(kru.v0, 0, n);
}
}
}b;
void init(int n, int v0)
{
Old.init(n); b.dp[v0] = {v0, 0, 0};
for(int i=1; i<=n; i++)
{
a.f[i] = i; a.Minn_id[i] = i;
a.Minn_dis[i] = inf;
}
}
int main()
{
n = read();
for(int i=1; i<=n; i++)
{
string s1, s2; int v;
cin >> s1 >> s2 >> v;
if(mp[s1] == 0) {mp[s1] = ++mpcnt;}
if(mp[s2] == 0) {mp[s2] = ++mpcnt;}
int x = mp[s1], y = mp[s2];
a.addEdge(x, y, v);
if(x == mp[park]) {b.v0link.push_back({y, v});}
else if(y == mp[park]) {b.v0link.push_back({x, v});}
}
init(mpcnt, mp[park]);
a.v0 = mp[park];
cin >> k;
tot = a.kruskal(mpcnt);
b.solve(a, k, mpcnt);
printf("Total miles driven: %d\n", a.ans);
return 0;
}
时光花火,水月星辰