CodeForces 295B
给出\(n\)个点的有向图和一个排列,按照排列顺序删除有向图中的点, 输出每次删除后两点间最短路之和。
\(n≤ 500\)。
sol:
把逐个删除转换成逐个加点,每增加一个点就用Floyd更新一下最短路。
NOI 2007 社交网络
给定 \(n\) 个点 \(m\)条边的无向图,定义 \(C_{s,t}\) 为 \(s\) 到 \(t\) 的最短路条数,\(C_{s,t}(u)\) 为经过 \(u\) 的 \(s\) 到 \(t\) 的最短路条数。对于每个节点 \(u\),求 \(I(u) =\frac{\sum_{s,t} C_{s,t}(u)}{C_{s,t}}\)。
\(n≤ 100\)。
sol:
Floyd。对于\(C_{s,t}\),设\(f[k][i][j]\)为\(i\)到\(j\)的最短路条数,每次\(dis\)数组变小时重置,相等时\(+1\)。对于\(C_{s,t}(u)\),再维护个变量在\(dis\)更新时随之更新即可。
一道例题
给定 \(n\) 个点 \(m\) 条边的无向图,每走一步所有边的边权会从 \(w\) 变成 \(\frac1{1−w}\),求 1 到 n 的最短路。 \(1 ≤n,m≤ 5000\)。
sol:
手玩一下易得\(w\)变三次就变回来了,所以构建一个三层的图。记\((k,x)\)为第\(k\)层中的\(x\)点,原本\(u\)到\(v\)的边就变为\((1,u)\)到\((2,v)\)的边等以此类推。
World Finals 2011 H Mining Your Own Business
给定 \(n\) 个点 \(m\) 条边的无向图,你要标关键点,使得删去任意一个点后,其他所有点都能到达至少一个关键点。 最小化关键点个数,并求出最小的方案数。 复杂度要求线性。
sol:
经典题。按点双缩点建圆方树,若整个图都是个点双,易得答案为2;否则每个叶子点双都必须设一个关键点,其他点双内的点因为至少有两种路径到叶子,所以没必要设关键点。计数就只要把每个叶子点双内的点数乘起来即可。
UOJ Goodbye Jiawu B
给定 \(n\) 个点 \(m\) 条边的无向图,求哪些点删掉之后这个图会变成一棵树。 复杂度要求线性。
sol:
首先不能删割点。其次就爆删度数为\(m-n+2\)的节点就完事了。
BJOI 2013 压力
给定 \(n\) 个点 \(m\) 条边的无向图,每次操作将 \(u\),\(v\) 之间所有必须经过的点 权值加一,求操作完了之后每个点的权值。 \(n≤ 10^5,m,q≤ 2×10^6\)。
sol:
建圆方树。每次必经的点一定是割点,也就是圆方树中的圆点,于是考虑树上差分。
POI 2012 Festival
\(n\) 个变量 \(m\) 个条件,每个形如 \(x_i = x_j + 1\) 或 \(x_i ≤x_j\),求所有变量不同 取值个数的最大值。 \(n≤ 600\)。
sol:
对于每个形如\(x_i = x_j + 1\) 的式子可以转化为\(x_i\leq x_j+1\)和\(x_j\leq x_i-1\)。建出差分约束图,考虑用Tarjan缩点,易得任意两个强连通分量之间取值都不会重复。现在的问题就简化为每个强连通分量里可以有多少个取值。因为每条边连接的两个点之间的差值不会超过\(1\),所以它们的取值一定在整数上连续,故取值个数为最长路长度\(+1\)。最终答案即为每个强连通分量的答案之和。
SCOI 2011 糖果
\(n\) 个变量 \(m\) 个条件,每个形如 \(x_i = x_j\),\(x_i ≤x_j\),\(x_i ≥x_j\),\(x_i < x_j\), \(x_i > x_j\),求和最小的非负整数解。 \(n,m≤ 10^5\)。
sol:
\(x_i = x_j\)可转化为\(x_i\leq x_j\)和\(x_j\leq x_i\);\(x_i < x_j\)和 \(x_i > x_j\)也类似转化成小于等于的形式。缩点,有一个性质就是图中没有正权边,所以每一个强连通分量里的边必定全是零。那就只要按拓扑序逆序一遍递推即可。
NOI 2017 游戏
小 L 计划进行\(n\)场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏。
小 L 的赛车有三辆,分别用大写字母A、B、C表示。地图一共有四种,分别用小写字母\(x,a,b,c\)表示。其中,赛车A不适合在地图\(a\)上使用,赛车B不适合在地图\(b\)上使用,赛车C不适合在地图\(c\)上使用,而地图\(x\)则适合所有赛车参加。适合所有赛车参加的地图并不多见,最多只会有\(d\)张。小 L 对游戏有一些特殊的要求,这些要求可以用四元组 \((i, h_i, j, h_j)\)来描述,表示若在第\(i\)场使用型号为\(h_i\) 的车子,则第\(j\)场游戏要使用型号为\(h_j\) 的车子。如果有多种方案,输出任意一种,如果无解,输出 \(-1\)。
sol:
这题唯一的难点就在于有一种适合三种地图的赛车。但很快就会发现这其实是假的,因为这种地图只有\(8\)张,所以只要枚举这种地图用A车或B车,用B车或C车。这样其实就已经涵盖了所有情况。复杂度\(O(N\times 2^d)\)
#include
using namespace std;
const int N=200005;
int n,d,m,px[N],gn,dfn[N],low[N],st[N],top,cnt,num,col[N];
char p[N],tmp='\0';bool vis[N];
struct node{int x,y;char c1,c2;} game[N];
vector ver[N];
inline int turn(int x,char c){
switch(p[x]){
case 'a':return c=='B'?0:c=='C'?1:2;
case 'b':return c=='A'?0:c=='C'?1:2;
case 'c':return c=='A'?0:c=='B'?1:2;
}
return 2;
}
inline char out(int x,int y){
switch(p[x]){
case 'a':return y?'B':'C';
case 'b':return y?'A':'C';
case 'c':return y?'A':'B';
}
return 'X';
}
inline void tarjan(int x){
dfn[x]=low[x]=++cnt;st[++top]=x;vis[x]=1;
for(int i=0;id){sol();return;}
p[px[x]]='a';dfs(x+1);
p[px[x]]='b';dfs(x+1);
p[px[x]]='x';
}
int main(){
scanf("%d%d%s%d",&n,&d,p,&m);d=0;
for(int i=0;i<=n;i++){
swap(tmp,p[i]);
if(p[i]=='x') px[++d]=i;
}
for(int i=1;i<=m;i++){
int x,y;char c1[5],c2[5];
scanf("%d%s%d%s",&x,c1,&y,c2);
if(p[x]=='x'||p[y]=='x'){
game[++gn].c1=c1[0];game[gn].c2=c2[0];
game[gn].x=x;game[gn].y=y;continue;
}
link(x,y,c1[0],c2[0]);
}
dfs(1);printf("-1");return 0;
}