-
Dijkstra算法
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<LL ,int>
const LL N = 1e5 + 10;
struct edge {
int u, v;
LL w;
edge(int u, int v, LL w) :u(u), v(v), w(w){}
};
vector<vector<edge> > e(N);
int n, m, s, visit[N];
LL dis[N];
void dijk() {
priority_queue<P, vector<P>, greater<P> > q;
dis[s] = 0;
q.push(P(dis[s], s));
while (!q.empty()) {
int u = q.top().second;
q.pop();
if (visit[u]) continue;
visit[u] = 1;
for (auto i : e[u]) {
if (dis[i.v] > dis[u] + i.w) {
dis[i.v] = dis[u] + i.w;
q.push(P(dis[i.v], i.v));
}
}
}
}
void solve() {
cin >> n >> m >> s;
for (int i = 0; i < m; ++i) {
int u, v;
LL w;
cin >> u >> v >> w;
e[u].push_back(edge(u, v, w));
}
memset(dis, 0x3f, sizeof(dis));
dijk();
for (int i = 1; i <= n; ++i) {
cout << dis[i] << " ";
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin >> _t;
while (_t--) {
solve();
}
return 0;
}
-
SPFA算法
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<LL ,int>
const LL N = 1e5 + 10;
struct edge {
int u, v;
LL w;
edge(int u, int v, LL w) :u(u), v(v), w(w) {}
};
int n, m;
int inq[N], cnt[N];
LL dis[N];
vector<vector<edge> > e(N);
int spfa(int u) {
memset(dis, 0x3f, sizeof(dis));
memset(inq, 0, sizeof(inq));
memset(cnt, 0, sizeof(cnt));
queue<int> q;
q.push(u);
inq[u] = 1;
cnt[u] = 1;
dis[u] = 0;
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = 0;
for (auto i : e[u]) {
if (dis[i.v] > dis[u] + i.w) {
dis[i.v] = dis[u] + i.w;
cnt[i.v]++;
if (cnt[i.v] >= n) return 1;
if (!inq[i.v]) {
q.push(i.v);
inq[i.v] = 1;
}
}
}
}
return 0;
}
void solve() {
cin >> n >> m;
e.clear();
e.resize(N);
for (int i = 0; i < m; ++i) {
int u, v;
LL w;
cin >> u >> v >> w;
if (w >= 0) e[v].push_back(edge(v, u, w));
e[u].push_back(edge(u, v, w));
}
if (spfa(1)) cout << "YES\n";
else cout << "NO\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
//_t = 1;
cin >> _t;
while (_t--) {
solve();
}
return 0;
}
//优化:deque,平均值
-
Floyd算法
void floyd(){
for(int k=1;k<=n;++k){
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
}
-
Johnson算法
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define P pair<int,int>
const double eps = 1e-8;
const ll INF = 1e18;
const ll N = 3e3 + 10;
struct edge {
int u, v, w;
};
vector<vector<edge> >e(N);
int n, m;
int inq[N], dis[N], dist[N][N], vis[N], cnt[N];
bool spfa() {
queue<int> q;
q.push(0);
dis[0] = 0;
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = 0;
for (auto i : e[u]) {
if (dis[u] + i.w < dis[i.v]) {
dis[i.v] = dis[u] + i.w;
cnt[i.v]++;
if (cnt[i.v] > n) return 0;
if (!inq[i.v]) {
inq[i.v] = 1;
q.push(i.v);
}
}
}
}
return 1;
}
void dijk(int x) {
priority_queue<P, vector<P>, greater<P> > q;
dist[x][x] = 0;
q.push({ dist[x][x],x });
while (!q.empty()) {
int u = q.top().second;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (auto i : e[u]) {
if (dist[x][u] + i.w < dist[x][i.v]) {
dist[x][i.v] = dist[x][u] + i.w;
q.push({ dist[x][i.v],i.v });
}
}
}
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({ u,v,w });
}
for (int i = 1; i <= n; ++i) e[0].push_back({ 0,i,0 });
memset(dis, 0x3f, sizeof(dis));
if (!spfa()) {
cout << -1;
return;
}
for (int i = 1; i <= n; ++i) {
for (auto& j : e[i]) {
j.w += dis[i] - dis[j.v];
}
}
memset(dist, 0x3f, sizeof(dist));
for (int i = 1; i <= n; ++i) {
memset(vis, 0, sizeof(vis));
dijk(i);
}
for (int i = 1; i <= n; ++i) {
ll ans = 0;
for (int j = 1; j <= n; ++j) {
if (dist[i][j] == 0x3f3f3f3f) dist[i][j] = 1e9;
else dist[i][j] -= dis[i] - dis[j];
ans += 1ll * j * dist[i][j];
}
cout << ans << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
多层图Dijkstra
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const LL N = 11e4 + 10;
int n, m,k,st,en;
int vis[N], dis[N];
struct edge {
int u, v, w;
edge(int u, int v, int w) :u(u), v(v), w(w) {}
};
vector<vector<edge> > e(N);
void dijk() {
memset(dis, 0x3f, sizeof(dis));
priority_queue<P, vector<P>, greater<P> > q;
dis[st] = 0;
q.push(P(dis[st], st));
while (!q.empty()) {
int u = q.top().second;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (auto i : e[u]) {
if (dis[i.v] > dis[u] + i.w) {
dis[i.v] = dis[u] + i.w;
q.push(P(dis[i.v], i.v));
}
}
}
}
void solve() {
cin >> n >> m >> k >> st >> en;
for (int i = 0; i < m; ++i) {
int x, y, c;
cin >> x >> y >> c;
for (int j = 0; j <= k; ++j) {
e[x + n * j].push_back(edge(x + n * j, y + n * j, c));
e[y + n * j].push_back(edge(y + n * j, x + n * j, c));
if (j != k) {
e[x + n * j].push_back(edge(x + n * j, y + n * (j + 1), 0));
e[y + n * j].push_back(edge(y + n * j, x + n * (j + 1), 0));
e[en + n * j].push_back(edge(en + n * j, en + n * (j + 1), 0));
}
}
}
dijk();
cout << dis[en + n * k];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin >> _t;
while (_t--) {
solve();
}
return 0;
}
-
差分约束
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e3 + 10;
struct edge {
int u, v, w;
edge(int u,int v,int w):u(u),v(v),w(w){}
};
vector<vector<edge> >e(N);
int dist[N],inq[N],cnt[N],n,m;
bool spfa() {
dist[0] = 0;
queue<int> q;
q.push(0);
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = 0;
for (edge i : e[u]) {
int v = i.v, w = i.w;
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
if (!inq[v]) {
inq[v] = 1;
cnt[v]++;
if (cnt[v] > n) return 0;
q.push(v);
}
}
}
}
return 1;
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) e[0].push_back(edge(0, i, 0));
for (int i = 1; i <= m; ++i) {
int u, v, w;
cin >> u >> v >> w;
e[v].push_back(edge(v, u, w));
}
memset(dist, 0x3f, sizeof(dist));
if (!spfa()) cout << "NO";
else {
for (int i = 1; i <= n; ++i) cout << dist[i] << " ";
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
传递闭包
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define LL long long
int dis[110][110];
int n,m;
void floyd(){
for(int k=1;k<=n;++k){
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
}
int main(){
cin>>n>>m;
memset(dis,0x3f,sizeof(dis));
for(int i=0;i<m;++i){
int a,b;
cin>>a>>b;
dis[a][b]=1;
}
floyd();
int ans=n;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(i!=j&&dis[i][j]==0x3f3f3f3f&&dis[j][i]==0x3f3f3f3f){
ans--;
break;
}
}
}
cout<<ans;
return 0;
}
-
k短路径
P2901 [USACO08MAR]Cow Jogging G
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e3 + 10;
struct edge {
int u, v, w;
edge(int u,int v,int w):u(u),v(v),w(w){}
};
struct node {
int id;
LL g, h;
node(int id,LL g,LL h):id(id),g(g),h(h){}
bool operator<(const node a)const {
return g + h > a.g + a.h;
}
};
vector<vector<edge> >e(N);
vector<vector<edge> >e2(N);
int n, m, k;
LL dis[N], cnt[N],vis[N],ans[110];
void dijk(int x) {
dis[x] = 0;
priority_queue<P, vector<P>, greater<P> >q;
q.push(P(dis[x], x));
while (!q.empty()) {
int u = q.top().second;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (auto i : e2[u]) {
if (dis[i.v] > dis[u] + i.w) {
dis[i.v] = dis[u] + i.w;
q.push(P(dis[i.v],i.v));
}
}
}
}
void astar(int s, int t, int k) {
priority_queue<node> q;
q.push(node(s, 0, dis[s]));
while (!q.empty()) {
node u = q.top();
q.pop();
cnt[u.id]++;
if (u.id == t) {
ans[cnt[u.id]] = u.g;
if (cnt[u.id] == k) return;
}
for (auto i : e[u.id]) {
q.push(node(i.v, u.g+i.w, dis[i.v]));
}
}
}
void solve() {
cin >> n >> m >> k;
for (int i = 1; i <= m; ++i) {
int x, y, z;
cin >> x >> y >> z;
e[x].push_back(edge(x, y, z));
e2[y].push_back(edge(y, x, z));
}
memset(dis, 0x3f, sizeof(dis));
for (int i = 1; i <= k; ++i) ans[i] = -1;
dijk(1);
astar(n, 1, k);
for (int i = 1; i <= k; ++i) {
cout << ans[i] << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
Kruskal算法
#include<iostream>
#include<algorithm>
using namespace std;
const LL N = 5e3 + 10;
const LL M = 2e5 + 10;
int f[N], cnt[N],n,m;
struct edge {
int u, v, w;
edge(int u,int v,int w):u(u),v(v),w(w){}
edge(){}
bool operator<(const edge a)const {
return w < a.w;
}
}e[M];
void init() {
for (int i = 1; i <= n; ++i) {
f[i] = i;
cnt[i] = 0;
}
}
int find(int x) {
if (x == f[x]) return x;
return f[x] = find(f[x]);
}
void merge(int x, int y) {
x = find(x);
y = find(y);
if (cnt[x] > cnt[y]) f[y] = x;
else {
if (cnt[x] == cnt[y]) cnt[y]++;
f[x] = y;
}
}
bool query(int x, int y) {
return find(x) == find(y);
}
int main() {
cin >> n >> m;
long long ans = 0;
int cur = 0;
init();
for (int i = 0; i < m; ++i) {
int x, y, z;
cin >> x >> y >> z;
e[i] = edge(x, y, z);
}
sort(e, e + m);
for (int i = 0; i < m; ++i) {
if (query(e[i].u, e[i].v)==0) {
merge(e[i].u, e[i].v);
ans += e[i].w;
cur++;
}
if (cur == n - 1) break;
}
if (cur == n - 1) cout << ans;
else cout << "orz";
return 0;
}
-
Prim算法
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
const LL N = 5e3 + 10;
int n, m, vis[N];
LL ans;
struct edge {
int u, v, w;
edge(int u, int v, int w) :u(u), v(v), w(w) {}
};
struct node {
int id, dis;
node(int id, int dis) :id(id), dis(dis) {}
bool operator<(const node a)const {
return dis > a.dis;
}
};
vector<vector<edge> > e(N);
bool prim() {
int cnt = 0;
priority_queue<node> q;
q.push(node(1, 0));
while (!q.empty()) {
node u = q.top();
q.pop();
if (vis[u.id]) continue;
vis[u.id] = 1;
ans += u.dis;
cnt++;
for (auto i : e[u.id]) {
if (vis[i.v]) continue;
q.push(node(i.v, i.w));
}
if (cnt == n) return 1;
}
return 0;
}
void solve() {
cin >> n >> m;
ans = 0;
for (int i = 0; i < m; ++i) {
int x, y, z;
cin >> x >> y >> z;
e[x].push_back(edge(x, y, z));
e[y].push_back(edge(y, x, z));
}
if (prim()) cout << ans;
else cout << "orz";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
严格次小生成树
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 3e5 + 10;
struct edge {
int u, v, w;
edge(){}
edge(int u, int v, int w) :u(u), v(v), w(w){}
bool operator<(const edge a)const {
return w < a.w;
}
}e[N];
int n, m, deep[N], f[N][20], dist1[N][20], dist2[N][20],fa[N],intree[N],d[N],cnt=0,num=0,cnta[N],cntb[N];
LL sum = 0,ans=INF;
vector<vector<edge> >p(N);
inline int read() {
char c = getchar(); int x = 0;
while (c < '0' || c > '9') { c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x;
}
inline void init() {
for (register int i = 1; i <= n; ++i) fa[i] = i;
}
inline int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
inline void merge(int a, int b) {
a = find(a);
b = find(b);
if (cnta[a] < cntb[b]) fa[a] = b;
else {
if (cnta[a] == cntb[b]) cnta[a]++;
fa[b] = a;
}
}
inline bool query(int a, int b) {
return find(a) == find(b);
}
void dfs(int x) {
for (edge i : p[x]) {
int v = i.v, w = i.w;
if (v == f[x][0]) continue;
deep[v] = deep[x] + 1;
f[v][0] = x;
dist1[v][0] = w;
for (register int j = 1; (1 << j) <= deep[v]; ++j) {
f[v][j] = f[f[v][j - 1]][j - 1];
d[0] = dist1[v][j - 1], d[1] = dist1[f[v][j - 1]][j - 1], d[2] = dist2[v][j - 1], d[3] = dist2[f[v][j - 1]][j - 1];
for (register int k = 0; k < 4; ++k) {
if (d[k] > dist1[v][j]) dist2[v][j] = dist1[v][j],dist1[v][j] = d[k] ;
else if (d[k] != dist1[v][j] && d[k] > dist2[v][j]) dist2[v][j] = d[k];
}
}
dfs(v);
}
}
int lca(int x, int y,int w) {
if (deep[x] < deep[y]) swap(x, y);
for (register int i = 19; i >= 0; --i) {
if (deep[f[x][i]] >= deep[y]) {
d[++num] = dist1[x][i];
d[++num] = dist2[x][i];
x = f[x][i];
}
}
if (x != y) {
for (register int i = 19; i >= 0; --i) {
if (f[x][i] != f[y][i]) {
d[++num] = dist1[x][i];
d[++num] = dist1[y][i];
d[++num] = dist2[x][i];
d[++num] = dist2[y][i];
x = f[x][i];
y = f[y][i];
}
}
d[++num] = dist1[x][0];
d[++num] = dist1[y][0];
}
int d1 = 0, d2 = 0;
for (register int i = 1; i <= num; ++i) {
if (d[i] > d1) d2 = d1,d1 = d[i];
else if (d[i] != d1 && d[i] > d2) d2 = d[i];
}
if (w == d1) return w - d2;
else return w - d1;
}
void solve() {
n=read(),m=read();
for (register int i = 1; i <= m; ++i) {
int u, v, w;
u = read(), v = read(), w = read();
e[i] = edge(u, v, w);
}
sort(e + 1, e + m + 1);
init();
for (register int i = 1; i <= m; ++i) {
int u = e[i].u, v = e[i].v,w=e[i].w;
if (u == v) continue;
if (!query(u,v)) {
merge(u, v);
cnt++;
sum += w;
p[u].push_back(edge(u, v, w));
p[v].push_back(edge(v, u, w));
intree[i] = 1;
}
if (cnt == n - 1) break;
}
deep[1] = 1;
dfs(1);
for (register int i = 1; i <= m; ++i) {
if (intree[i]) continue;
int u = e[i].u, v = e[i].v,w=e[i].w;
if (u == v) continue;
num = 0;
ans = min(ans, sum + lca(u, v, w));
}
cout << ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
拓扑排序
void topo() {
queue<int> q;
for (int i = 1; i <= n; ++i) {
if (in[i] == 0) q.push(i);
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i : e[u]) {
in[i]--;
if (in[i] == 0) q.push(i);
}
}
}
-
基环树DP
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const LL N = 1e5 + 10;
vector<vector<int> >e(N);
LL n, p[N],in[N],vis[N],dp[N][2];
double k;
void dfs(int a,int b,int x) {
vis[x]=1;
dp[x][0] = dp[x][1] = 0;
for (int i : e[x]) {
if (vis[i]||x == b && i == a) continue;
dfs(a, b, i);
dp[x][1] += dp[i][0];
dp[x][0] += max(dp[i][1], dp[i][0]);
}
dp[x][1] += p[x];
}
void topo() {
queue<int> q;
for (int i = 0; i < n; ++i) {
if (in[i] == 1) q.push(i);
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i : e[u]) {
in[i]--;
if (in[i] == 1) q.push(i);
}
}
}
void solve() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> p[i];
for (int i = 0; i < n; ++i) {
int a, b;
cin >> a >> b;
e[a].push_back(b);
e[b].push_back(a);
in[a]++;
in[b]++;
}
cin >> k;
topo();
for (int i = 0; i < n; ++i) {
if (in[i] == 2) {
for (int j : e[i]) {
if (in[j] == 2) {
dfs(j, i, i);
LL ans = dp[i][0];
memset(vis, 0, sizeof(vis));
dfs(i, j, j);
cout << setiosflags(ios::fixed) << setprecision(1) << max(ans, dp[j][0]) * k;
return;
}
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
割点
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const LL N = 2e4 + 10;
vector<vector<int> >e(N);
int n, m, num[N], low[N], cnt = 0,dfn = 0,cut[N];
void tarjan(int x,int fa) {
num[x] = low[x] = ++dfn;
int child = 0;
for (int i : e[x]) {
if (num[i] == 0) {
child++;
tarjan(i, x);
low[x] = min(low[x], low[i]);
if (num[x] <= low[i] && x != fa) cut[x] = 1;//num[x]<low[i]割边
}
else if (i != fa) low[x] = min(low[x], num[i]);
}
if (x == fa && child >= 2) cut[x] = 1;
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int x, y;
cin >> x >> y;
e[x].push_back(y);
e[y].push_back(x);
}
for (int i = 1; i <= n; ++i) {
if (!num[i]) tarjan(i,i);
}
for (int i = 1; i <= n; ++i) cnt += cut[i];
cout << cnt << '\n';
for (int i = 1; i <= n; ++i) {
if (cut[i]) cout << i << " ";
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
点双连通分量
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 5e5 + 10;
vector<vector<int> >e(N);
vector<vector<int> >vdcc(N);
int num[N], low[N], dfn, tot;
stack<int> st;
void tarjan(int x, int fa) {
st.push(x);
num[x] = low[x] = ++dfn;
int child = 0;
for (int i : e[x]) {
if (!num[i]) {
child++;
tarjan(i, x);
low[x] = min(low[x], low[i]);
if (num[x] <= low[i]) {
tot++;
int u = -1;
while (u != i) {
u = st.top();
st.pop();
vdcc[tot].push_back(u);
}
vdcc[tot].push_back(x);
}
}
else if (i != fa) low[x] = min(low[x], num[i]);
}
if (x == fa && child == 0) vdcc[++tot].push_back(x);
}
void solve() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
for (int i = 1; i <= n; ++i) {
if (!num[i]) tarjan(i, i);
}
cout << tot << '\n';
for (int i = 1; i <= tot; ++i) {
cout << vdcc[i].size() << " ";
for (int j : vdcc[i]) cout << j << " ";
cout << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
边双连通分量
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 4e6 + 10;
vector<vector<int> >edcc(N);
int h[N], nx[N], to[N], cnt = 1;
int num[N], low[N], dfn, tot;
stack<int> st;
void add(int x, int y) {
nx[++cnt] = h[x], h[x] = cnt, to[cnt] = y;
}
void tarjan(int x, int edge) {
st.push(x);
num[x] = low[x] = ++dfn;
for (int i = h[x]; i; i = nx[i]) {
int v = to[i];
if (!num[v]) {
tarjan(v, i);
low[x] = min(low[x], low[v]);
}
else if ((i ^ 1) != edge) low[x] = min(low[x], num[v]);
}
if (num[x] == low[x]) {
++tot;
int u = -1;
while (u != x) {
u = st.top();
st.pop();
edcc[tot].push_back(u);
}
}
}
void solve() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int u, v;
cin >> u >> v;
if (u > v) swap(u, v);
add(u, v), add(v, u);
}
for (int i = 1; i <= n; ++i) {
if (!num[i]) tarjan(i, -1);
}
cout << tot << '\n';
for (int i = 1; i <= tot; ++i) {
cout << edcc[i].size() << " ";
for (int j : edcc[i]) cout << j << " ";
cout << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
tarjan算法/缩点
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const LL N = 1e4 + 10;
vector<vector<int> >e(N);
vector<vector<int> >p(N);
stack<int> st;
int a[N],n,m,num[N],low[N],sccno[N],cnt=0,val[N],in[N],dp[N],vis[N],dfn=0;
void tarjan(int x) {
st.push(x);
num[x] = low[x] = ++dfn;
for (int i : e[x]) {
if (num[i] == 0) {
tarjan(i);
low[x] = min(low[x], low[i]);
}
else if (sccno[i] == 0) low[x] = min(low[x], num[i]);
}
if (low[x] == num[x]) {
cnt++;
int u = -1;
while (u != x) {
u = st.top();
st.pop();
sccno[u] = cnt;
}
}
}
void topo() {
queue<int> q;
for (int i = 1; i <= cnt; ++i) {
if (in[i] == 0)q.push(i);
dp[i] = val[i];
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i : p[u]) {
dp[i] = max(dp[i], dp[u] + val[i]);
in[i]--;
if (in[i] == 0) q.push(i);
}
}
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
for (int i = 1; i <= m; ++i) {
int u, v;
cin >> u >> v;
e[u].push_back(v);
}
for (int i = 1; i <= n; ++i) {
if (num[i] == 0) tarjan(i);
}
for (int i = 1; i <= n; ++i) {
for (int j : e[i]) {
if (sccno[i] != sccno[j]) {
p[sccno[i]].push_back(sccno[j]);
in[sccno[j]]++;
}
}
}
topo();
int ans = 0;
for (int i = 1; i <= cnt; ++i) {
ans = max(ans, dp[i]);
}
cout << ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
2-SAT问题
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const int N = 2e6 + 10;
vector<vector<int> >e(N);
int n, m, num[N], low[N], sscno[N], dfn = 0, cnt = 0;
stack<int> st;
void tarjan(int x) {
st.push(x);
num[x] = low[x] = dfn++;
for (int i : e[x]) {
if (!num[i]) {
tarjan(i);
low[x] = min(low[x], low[i]);
}
else if (!sscno[i]) {
low[x] = min(low[x], num[i]);
}
}
if (low[x] == num[x]) {
++cnt;
int u = -1;
while (u != x) {
u = st.top();
st.pop();
sscno[u] = cnt;
}
}
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int a, b, c, d;
cin >> a >> b >> c >> d;
e[a + (1 - b) * n].push_back(c + d * n);
e[c + (1 - d) * n].push_back(a + b * n);
}
for (int i = 1; i <= 2 * n; ++i) {
if (!num[i])tarjan(i);
}
for (int i = 1; i <= n; ++i) {
if (sscno[i] == sscno[i + n]) {
cout << "IMPOSSIBLE";
return;
}
}
cout << "POSSIBLE\n";
for (int i = 1; i <= n; ++i) {
cout << (sscno[i] > sscno[i + n]) << " ";
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
EK算法
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e4 + 10;
struct edge {
int u, v, n;
LL f;
edge() {}
edge(int u, int v, LL f, int n) :u(u), v(v), f(f), n(n) {}
}e[N];
LL flow[N];
int n, m, s, t, cnt = 1, head[N], pre[N];
void add(int u, int v, LL f) {
cnt++;
e[cnt] = edge(u, v, f, head[u]);
head[u] = cnt;
}
bool bfs() {
memset(pre, 0, sizeof(pre));
flow[s] = INF;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
if (u == t) return 1;
for (int i = head[u]; i; i = e[i].n) {
int v = e[i].v;
LL f = e[i].f;
if (f > 0 && !pre[v]) {
flow[v] = min(flow[u], f);
pre[v] = i;
q.push(v);
}
}
}
return 0;
}
LL MaxFlow() {
LL ans = 0;
while (1) {
if (!bfs()) break;
ans += flow[t];
int cur = t;
while (cur != s) {
e[pre[cur]].f -= flow[t];
e[pre[cur] ^ 1].f += flow[t];
cur = e[pre[cur]].u;
}
}
return ans;
}
void solve() {
cin >> n >> m >> s >> t;
for (int i = 1; i <= m; ++i) {
int u, v;
LL f;
cin >> u >> v >> f;
add(u, v, f);
add(v, u, 0);
}
cout << MaxFlow();
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
Dinic算法
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e4 + 10;
struct edge {
int u, v, n;
LL f;
edge() {}
edge(int u, int v, LL f, int n) :u(u), v(v), f(f), n(n) {}
}e[MAXN];
int n, m, s, t, cnt = 1, head[N],deep[N],now[N];
void add(int u, int v, LL f) {
cnt++;
e[cnt] = edge(u, v, f, head[u]);
head[u] = cnt;
}
bool bfs() {
memcpy(now, head, sizeof(head));
deep[s] = 1;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; i; i = e[i].n) {
int v = e[i].v;
LL f = e[i].f;
if (f > 0 && !deep[v]) {
deep[v] = deep[u] + 1;
if (v == t) return 1;
q.push(v);
}
}
}
return 0;
}
LL dfs(int u, LL sum) {
if (u == t) return sum;
LL flow = 0;
for (int i = now[u]; i&∑ i = e[i].n) {
now[u] = i;
int v = e[i].v;
LL f = e[i].f;
if (f > 0 && deep[v] == deep[u] + 1) {
LL k = dfs(v, min(sum, f));
if (k == 0) deep[v] = 0;
e[i].f -= k;
e[i ^ 1].f += k;
flow += k;
sum -= k;
}
}
return flow;
}
void solve() {
cin >> n >> m >> s >> t;
for (int i = 1; i <= m; ++i) {
int u, v;
LL f;
cin >> u >> v >> f;
add(u, v, f);
add(v, u, 0);
}
LL ans = 0;
while (bfs()) ans += dfs(s, INF);
cout << ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
ISAP算法
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e4 + 10;
struct edge {
int u, v, n;
LL f;
edge() {}
edge(int u, int v, LL f, int n) :u(u), v(v), f(f), n(n) {}
}e[MAXN];
int n, m, s, t, cnt = 1, head[N], pre[N],now[N],gap[N],deep[N];
void add(int u, int v, LL f) {
cnt++;
e[cnt] = edge(u, v, f, head[u]);
head[u] = cnt;
}
void bfs() {
memcpy(now, head, sizeof(head));
deep[t] = 1;
queue<int> q;
q.push(t);
while (!q.empty()) {
int u = q.front();
q.pop();
gap[deep[u]]++;
for (int i = head[u]; i; i = e[i].n) {
int v = e[i].v;
LL f = e[i^1].f;
if (!deep[v] && f) {
deep[v] = deep[u] + 1;
q.push(v);
}
}
}
}
LL augement() {
int cur = t;
LL flow = INF;
while (cur != s) {
flow = min(flow, e[pre[cur]].f);
cur = e[pre[cur]].u;
}
cur = t;
while (cur != s) {
e[pre[cur]].f -= flow;
e[pre[cur] ^ 1].f += flow;
cur = e[pre[cur]].u;
}
return flow;
}
void isap() {
bfs();
LL flow = 0;
int u = s;
while (deep[s] <= n) {
if (u == t) {
flow += augement();
u = s;
}
bool ok = 0;
for (int i = now[u]; i; i = e[i].n) {
int v = e[i].v;
LL f = e[i].f;
if (f && deep[v] + 1 == deep[u]) {
ok = 1;
now[u] = i;
pre[v] = i;
u = v;
break;
}
}
if (!ok) {
if (!--gap[deep[u]]) break;
int mindeep = n + 10;
for (int i = head[u]; i; i = e[i].n) {
int v = e[i].v;
LL f = e[i].f;
if (f) mindeep = min(mindeep, deep[v]);
}
deep[u] = mindeep + 1;
gap[deep[u]]++;
now[u] = head[u];
if (u != s) u = e[pre[u]].u;
}
}
cout << flow;
}
void solve() {
cin >> n >> m >> s >> t;
for (int i = 1; i <= m; ++i) {
int u, v;
LL f;
cin >> u >> v >> f;
add(u, v, f);
add(v, u, 0);
}
isap();
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
HLPP算法
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 3e5 + 10;
struct edge {
int u, v, n;
LL f;
edge() {}
edge(int u, int v, LL f, int n) :u(u), v(v), f(f), n(n) {}
}e[N];
LL flow[N], ex[N];
int n, m, s, t, cnt = 1, head[N], pre[N], now[N], gap[N], deep[N], inq[N];
struct cmp {
bool operator()(const int a, const int b) const {
return deep[a] < deep[b];
}
};
int read() {
int res = 0;
char ch = getchar();
while (ch < '0' || ch>'9') { ch = getchar(); }
while (ch >= '0' && ch <= '9') { res = res * 10 + ch - '0'; ch = getchar(); }
return res;
}
void add(int u, int v, LL f) {
cnt++;
e[cnt] = edge(u, v, f, head[u]);
head[u] = cnt;
}
void bfs() {
for (int i = 1; i <= n; ++i) deep[i] = n + 1;
deep[t] = 1;
queue<int> q;
q.push(t);
while (!q.empty()) {
int u = q.front();
q.pop();
for (register int i = head[u]; i; i = e[i].n) {
int v = e[i].v;
LL f = e[i ^ 1].f;
if (f && deep[v] == n + 1) {
deep[v] = deep[u] + 1;
q.push(v);
}
}
}
}
void hlpp() {
bfs();
priority_queue<int, vector<int>, cmp> q;
deep[s] = n + 1;
for (register int i = 1; i <= n; ++i)gap[deep[i]]++;
for (register int i = head[s]; i; i = e[i].n) {
int v = e[i].v;
LL f = e[i].f;
if (f) {
e[i].f -= f;
e[i ^ 1].f += f;
ex[s] -= f;
ex[v] += f;
if (!inq[v] && v != s && v != t) {
inq[v] = 1;
q.push(v);
}
}
}
while (!q.empty()) {
int u = q.top();
q.pop();
inq[u] = 0;
for (register int i = head[u]; i; i = e[i].n) {
int v = e[i].v;
LL f = e[i].f;
if (f && deep[v] + 1 == deep[u]) {
int k = min(ex[u], f);
e[i].f -= k;
e[i ^ 1].f += k;
ex[u] -= k;
ex[v] += k;
if (!inq[v] && v != s && v != t) {
inq[v] = 1;
q.push(v);
}
if (!ex[u]) break;
}
}
if (ex[u]) {
if (!--gap[deep[u]]) {
for (register int i = 1; i <= n; i++) {
if (i != s && i != t && deep[i] > deep[u] && deep[i] < n + 1) {
deep[i] = n + 1;
}
}
}
int mindeep = 0x3f3f3f3f;
for (register int i = head[u]; i; i = e[i].n) {
int v = e[i].v;
LL f = e[i].f;
if (f) mindeep = min(mindeep, deep[v]);
}
deep[u] = mindeep + 1;
gap[deep[u]]++;
inq[u] = 1;
q.push(u);
}
}
cout << ex[t];
}
void solve() {
n = read(), m = read(), s = read(), t = read();
for (register int i = 1; i <= m; ++i) {
int u, v;
LL f;
u = read(), v = read(), f = read();
add(u, v, f);
add(v, u, 0);
}
hlpp();
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
二分图最大匹配(匈牙利算法)
最大流做法
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e4 + 10;
int n, m, p,sum=0,match[N],vis[N];
vector<vector<int> > e(N);
bool dfs(int x) {
for (int i:e[x]) {
if (!vis[i]) {
vis[i] = 1;
if (!match[i] || dfs(match[i])) {
match[i] = x;
return 1;
}
}
}
return 0;
}
void solve() {
cin >> n >> m >> p;
for (int i = 1; i <= p; ++i) {
int x, y;
cin >> x >> y;
e[x].push_back(y);
}
for (int i = 1; i <= n; ++i) {
memset(vis, 0, sizeof(vis));
if (dfs(i)) sum++;
}
cout << sum;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
二分图最大权匹配(KM算法)
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e2 + 10;
int mx[N], my[N], pre[N], vx[N], vy[N], n, m;
LL slack[N], e[N][N], wx[N], wy[N], d;
void augement(int x) {
while (x) {
my[x] = pre[x];
int t = mx[pre[x]];
mx[pre[x]] = x;
x = t;
}
}
void bfs(int x) {
queue<int> q;
q.push(x);
while (1) {
while (!q.empty()) {
int u = q.front();
q.pop();
vx[u] = 1;
for (int i = 1; i <= n; ++i) {
if (!vy[i] && wx[u] + wy[i] - e[u][i] < slack[i]) {
slack[i] = wx[u] + wy[i] - e[u][i];
pre[i] = u;
if (!slack[i]) {
vy[i] = 1;
if (!my[i]) {
augement(i);
return;
}
else q.push(my[i]);
}
}
}
}
d = INF;
for (int i = 1; i <= n; ++i)if (!vy[i]) d = min(d, slack[i]);
for (int i = 1; i <= n; ++i) {
if (vx[i]) wx[i] -= d;
if (vy[i]) wy[i] += d;
else slack[i] -= d;
}
for (int i = 1; i <= n; ++i) {
if (!vy[i] && !slack[i]) {
vy[i] = 1;
if (!my[i]) {
augement(i);
return;
}
else q.push(my[i]);
}
}
}
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
e[i][j] = -INF;
}
}
for (int i = 1; i <= m; ++i) {
int x, y, w;
cin >> x >> y >> w;
e[x][y] = w;
wx[x] = max(wx[x], 1LL * w);
}
for (int i = 1; i <= n; ++i) {
memset(vx, 0, sizeof(vx));
memset(vy, 0, sizeof(vy));
fill(slack + 1, slack + n + 1, INF);
bfs(i);
}
LL ans = 0;
for (int i = 1; i <= n; ++i) ans += e[i][mx[i]];
cout << ans << '\n';
for (int i = 1; i <= n; ++i) cout << my[i] << " ";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
一般图最大匹配
待填
-
最小费用最大流
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e5 + 10;
struct edge {
int u, v, f, c,n;
edge(){}
edge(int u,int v,int f,int c,int n):u(u),v(v),f(f),c(c),n(n) {}
}e[N];
int head[N],pre[N],inq[N],dist[N],flow[N], cnt =1,n,m,s,t;
void add(int u, int v, int f, int c) {
cnt++;
e[cnt] = edge(u, v, f, c, head[u]);
head[u] = cnt;
}
bool spfa() {
memset(pre, 0, sizeof(pre));
memset(inq, 0, sizeof(inq));
memset(dist, 0x3f, sizeof(dist));
memset(flow, 0x3f, sizeof(flow));
dist[s] = 0;
inq[s] = 1;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = 0;
for (int i = head[u]; i; i = e[i].n) {
int v = e[i].v, f = e[i].f, c = e[i].c;
if (f&&dist[v] > dist[u] + c) {
dist[v] = dist[u] + c;
pre[v] = i;
flow[v] = min(flow[u], f);
if (!inq[v]) {
inq[v] = 1;
q.push(v);
}
}
}
}
if (dist[t] == 0x3f3f3f3f) return 0;
else return 1;
}
void maxflow() {
LL maxflow = 0, mincost = 0;
while (spfa()) {
int cur = t;
while (cur != s) {
e[pre[cur]].f -= flow[t];
e[pre[cur] ^ 1].f += flow[t];
cur = e[pre[cur]].u;
}
maxflow += flow[t];
mincost += 1LL*dist[t]*flow[t];
}
cout << maxflow << " " << mincost;
}
void solve() {
cin >> n >> m >> s >> t;
for (int i = 1; i <= m; ++i) {
int u, v, f, c;
cin >> u >> v >> f >> c;
add(u, v, f, c);
add(v, u, 0, -c);
}
maxflow();
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
有源汇上下界最大流
P5192 Zoj3229 Shoot the Bullet|东方文花帖|【模板】有源汇上下界最大流
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const int INF = 1e9;
const LL N = 1e6 + 10;
struct edge {
int u, v, f, n;
edge() {}
edge(int u, int v, int f, int n) :u(u), v(v), f(f), n(n) {}
}e[N];
int n, m, s1, s2, t1, t2, cnt, head[N],deep[N],gap[N],now[N],pre[N],fl[N];
void add(int u, int v, int f) {
cnt++;
e[cnt] = edge(u, v, f, head[u]);
head[u] = cnt;
}
void bfs(int s,int t) {
memcpy(now, head, sizeof(head));
memset(deep, 0, sizeof(deep));
memset(gap, 0, sizeof(gap));
deep[t] = 1;
queue<int> q;
q.push(t);
while (!q.empty()) {
int u = q.front();
q.pop();
gap[deep[u]]++;
for (int i = head[u]; i; i = e[i].n) {
int v = e[i].v, f = e[i^1].f;
if (f && !deep[v]) {
deep[v] = deep[u] + 1;
q.push(v);
}
}
}
}
int augement(int s,int t) {
int flow = INF, cur = t;
while (cur != s) {
flow = min(flow, e[pre[cur]].f);
cur = e[pre[cur]].u;
}
cur = t;
while (cur != s) {
e[pre[cur]].f -= flow;
e[pre[cur] ^ 1].f += flow;
cur = e[pre[cur]].u;
}
return flow;
}
LL isap(int s, int t) {
bfs(s,t);
LL flow = 0;
int u = s;
while (deep[s] <= n + m + 4) {
if (u == t) {
flow += augement(s,t);
u = s;
}
bool ok = 0;
for (int i = now[u]; i; i = e[i].n) {
int v = e[i].v, f = e[i].f;
if (f&&deep[v]+1==deep[u]) {
now[u] = i;
pre[v] = i;
ok = 1;
u = v;
break;
}
}
if (!ok) {
if (!--gap[deep[u]]) break;
int mindeep = n+m+10;
for (int i = head[u]; i; i = e[i].n) {
int v = e[i].v, f = e[i].f;
if (f) mindeep = min(mindeep, deep[v]);
}
deep[u] = mindeep+1;
gap[deep[u]]++;
now[u] = head[u];
if(u!=s) u = e[pre[u]].u;
}
}
return flow;
}
void solve() {
while (cin >> n >> m) {
memset(fl, 0, sizeof(fl));
memset(head, 0, sizeof(head));
s1 = n + m + 1, t1 = n + m + 2, s2 = n + m + 3, t2 = n + m + 4,cnt=1;
LL sum = 0;
for (int i = 1; i <= m; ++i) {
int g;
cin >> g;
add(n + i, t1,INF);
add(t1, n + i,0);
fl[n + i] -= g, fl[t1] += g;
}
for (int i = 1; i <= n; ++i) {
int c, d;
cin >> c >> d;
add(s1, i, d);
add(i, s1, 0);
for (int j = 1; j <=c; ++j) {
int t, l, r;
cin >> t >> l >> r;
t++;
add(i, n + t, r-l);
add(n + t, i, 0);
fl[i] -= l, fl[n + t] += l;
}
}
for (int i = 1; i <= n + m + 2; ++i) {
if (fl[i] < 0) {
add(i, t2, -fl[i]);
add(t2, i, 0);
}
else {
add(s2, i, fl[i]);
add(i,s2,0);
sum += fl[i];
}
}
add(t1, s1,INF);
add(s1, t1, 0);
if (isap(s2, t2) != sum) {
cout << -1 << "\n\n";
continue;
}
e[cnt].f = e[cnt ^ 1].f = 0;
cout << sum + isap(s1, t1) << "\n\n";
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
最小树形图(朱刘算法)
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e9;
const ll N = 1e2 + 10;
stack<int> st;
int n, m, r;
int d[N][N], bd[N][N], num[N], low[N], sccno[N], vis[N], pre[N], dfn, cnt;
void dfs(int x) {
vis[x] = 1;
for (int i = 1; i <= n; ++i) {
if (d[x][i] != INF && !vis[i]) dfs(i);
}
}
void tarjan(int x) {
st.push(x);
num[x] = low[x] = ++dfn;
if (num[pre[x]] == 0) {
tarjan(pre[x]);
low[x] = min(low[x], low[pre[x]]);
}
else if (sccno[pre[x]] == 0) low[x] = min(low[x], num[pre[x]]);
if (low[x] == num[x]) {
cnt++;
int u = -1;
while (u != x) {
u = st.top();
st.pop();
sccno[u] = cnt;
}
}
}
void solve() {
cin >> n >> m >> r;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) d[i][j] = INF;
}
for (int i = 1; i <= m; ++i) {
int u, v, w;
cin >> u >> v >> w;
if (u != v && v != r) d[u][v] = min(d[u][v], w);
}
dfs(r);
for (int i = 1; i <= n; ++i) {
if (!vis[i]) {
cout << -1;
return;
}
}
ll res = 0;
while (1) {
for (int i = 1; i <= n; ++i) {
pre[i] = i;
for (int j = 1; j <= n; ++j) {
if (d[j][i] < d[pre[i]][i]) pre[i] = j;
}
}
memset(num, 0, sizeof(num));
memset(sccno, 0, sizeof(sccno));
dfn = cnt = 0;
for (int i = 1; i <= n; ++i) {
if (!num[i]) tarjan(i);
}
if (cnt == n) {
for (int i = 1; i <= n; ++i) {
if (i == r) continue;
res += d[pre[i]][i];
}
break;
}
else {
for (int i = 1; i <= n; ++i) {
if (i == r) continue;
if (sccno[i] == sccno[pre[i]]) res += d[pre[i]][i];
}
for (int i = 1; i <= cnt; ++i) {
for (int j = 1; j <= cnt; ++j) bd[i][j] = INF;
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (d[i][j] != INF && sccno[i] != sccno[j]) {
if (sccno[pre[j]] == sccno[j]) bd[sccno[i]][sccno[j]] = min(bd[sccno[i]][sccno[j]], d[i][j] - d[pre[j]][j]);
else bd[sccno[i]][sccno[j]] = min(bd[sccno[i]][sccno[j]], d[i][j]);
}
}
}
}
r = sccno[r];
n = cnt;
memcpy(d, bd, sizeof(bd));
}
cout << res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
Prufer序列
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e9;
const ll N = 5e6 + 10;
int f[N], p[N], out[N];
void solve() {
int n, op;
ll res = 0;
cin >> n >> op;
if (op == 1) {
for (int i = 1; i <= n - 1; ++i) {
cin >> f[i];
out[f[i]]++;
}
for (int i = 0, j = 1; i <= n - 2; ++j) {
while (out[j]) j++;
p[++i] = f[j];
while (i <= n - 2 && --out[p[i]] == 0 && p[i] < j) p[i + 1] = f[p[i]], i++;
}
for (int i = 1; i <= n - 2; ++i) res ^= 1ll * i * p[i];
}
else {
for (int i = 1; i <= n - 2; ++i) {
cin >> p[i];
out[p[i]]++;
}
p[n - 1] = n;
out[p[n - 1]]++;
for (int i = 0, j = 1; i <= n - 1; ++j) {
while (out[j]) j++;
f[j] = p[++i];
while (i <= n - 1 && --out[p[i]] == 0 && p[i] < j) f[p[i]] = p[i + 1], i++;
}
for (int i = 1; i <= n - 1; ++i) res ^= 1ll * i * f[i];
}
cout << res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
Cayley 公式:完全图有棵生成树。
-
仙人掌
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 2e4 + 10;
struct edge {
int u, v, w;
};
vector<vector<edge> >e(N);
vector<vector<edge> >p(N);
int newn, s[N];
int num[N], low[N], dfn, fa[N], fw[N];
int f[N][15], deep[N], dis[N], A, B;
void build(int u, int v, int w) {
newn++;
int tmp = v, sum = w;
while (tmp != u) {
s[tmp] = sum;
sum += fw[tmp];
tmp = fa[tmp];
}
s[newn] = s[u] = sum;
tmp = v;
while (tmp != u) {
p[newn].push_back({ newn,tmp,min(s[tmp],s[u] - s[tmp]) });
tmp = fa[tmp];
}
p[u].push_back({ u,newn,0 });
}
void tarjan(int x, int father) {
num[x] = low[x] = ++dfn;
for (auto i : e[x]) {
int v = i.v, w = i.w;
if (!num[v]) {
fa[v] = x, fw[v] = w;
tarjan(v, x);
low[x] = min(low[x], low[v]);
if (num[x] < low[v]) p[x].push_back({ x,v,w });
}
else if (v != father) low[x] = min(low[x], num[v]);
}
for (auto i : e[x]) {
int v = i.v, w = i.w;
if (num[x] < num[v] && fa[v] != x) build(x, v, w);
}
}
void dfs(int x, int father) {
deep[x] = deep[father] + 1;
f[x][0] = father;
for (int i = 1; (1 << i) <= deep[x]; ++i) f[x][i] = f[f[x][i - 1]][i - 1];
for (auto i : p[x]) {
int v = i.v;
dis[v] = dis[x] + i.w;
if (v != father) dfs(v, x);
}
}
int lca(int x, int y) {
if (deep[x] < deep[y]) swap(x, y);
for (int i = 14; i >= 0; --i) {
if (deep[f[x][i]] >= deep[y]) x = f[x][i];
}
if (x == y) return x;
for (int i = 14; i >= 0; --i) {
if (f[x][i] != f[y][i]) {
x = f[x][i];
y = f[y][i];
}
}
A = x, B = y;
return f[x][0];
}
void solve() {
int n, m, q;
cin >> n >> m >> q;
newn = n;
for (int i = 1; i <= m; ++i) {
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({ u,v,w });
e[v].push_back({ v,u,w });
}
tarjan(1, 0);
dfs(1, 0);
for (int i = 1; i <= q; ++i) {
int a, b;
cin >> a >> b;
int d = lca(a, b);
if (d <= n) cout << dis[a] + dis[b] - dis[d] * 2 << '\n';
else cout << dis[a] + dis[b] - dis[A] - dis[B] + min(abs(s[A] - s[B]), s[d] - abs(s[A] - s[B])) << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
双端队列
P4667 [BalticOI 2011 Day1]Switch the Lamp On
#include <iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long
#define P pair<int,int>
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e2 + 10;
struct node {
int x, y, dis;
};
int n, m;
int g[N][N], dis[N][N];
int d[4][2] = { {-1,-1},{-1,1},{1,-1},{1,1} }, ab[4] = { 2,1,1,2 }, cd[4][2] = { {-1,-1},{-1,0},{0,-1},{0,0} };
void bfs() {
memset(dis, 0x3f, sizeof(dis));
dis[1][1] = 0;
deque<node> dq;
dq.push_back({ 1,1,0 });
while (!dq.empty()) {
node u = dq.front();
dq.pop_front();
for (int i = 0; i < 4; ++i) {
int nx = u.x + d[i][0], ny = u.y + d[i][1];
int k = g[u.x + cd[i][0]][u.y + cd[i][1]] != ab[i];
if (nx >= 1 && nx <= n + 1 && ny >= 1 && ny <= m + 1 && dis[nx][ny] > dis[u.x][u.y] + k) {
dis[nx][ny] = dis[u.x][u.y] + k;
if (k == 0) dq.push_front({ nx,ny,dis[nx][ny] });
else dq.push_back({ nx,ny,dis[nx][ny] });
if (nx == n + 1 && ny == m + 1) break;
}
}
}
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
char ch;
cin >> ch;
if (ch == '/') g[i][j] = 1;
else g[i][j] = 2;
}
}
bfs();
if (dis[n + 1][m + 1] == 0x3f3f3f3f) cout << "NO SOLUTION";
else cout << dis[n + 1][m + 1];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
模拟退火
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>
using namespace std;
#define ll long long
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e2 + 10;
struct {
int x, y;
}a[N];
int n, f = 0, ans = 0;
int calc() {
int res = 0;
for (int i = 0; i < n; ++i) {
res += a[i].x + a[i].y;
if (i < n - 1) {
if (a[i].x == 10) res += a[i + 1].x + a[i + 1].y;
else if (a[i].x + a[i].y == 10) res += a[i + 1].x;
}
}
ans = max(ans, res);
return res;
}
void sa() {
for (double t = 1e4; t > 1e-4; t *= 0.99) {
int d1 = calc();
int x = rand() % n, y = rand() % n;
swap(a[x], a[y]);
if (f && a[n - 2].x != 10 || !f && a[n - 1].x == 10) swap(a[x], a[y]);
else {
int d2 = calc();
if (exp((d2 - d1) / t) < (double)rand() / RAND_MAX) swap(a[x], a[y]);
}
}
}
void solve() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> a[i].x >> a[i].y;
if (a[n - 1].x == 10) {
n++;
f = 1;
cin >> a[n - 1].x >> a[n - 1].y;
}
while ((double)clock() / CLOCKS_PER_SEC < 0.8) sa();
cout << ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}
-
爬山法
#include<iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<ctime>
using namespace std;
#define ll long long
#define P pair<int,int>
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e1 + 10;
int n;
double a[N][N], ans[N], dis[N], delta[N];
void calc() {
double avg = 0;
for (int i = 1; i <= n + 1; ++i) {
dis[i] = delta[i] = 0;
for (int j = 1; j <= n; ++j) {
dis[i] += (a[i][j] - ans[j]) * (a[i][j] - ans[j]);
}
dis[i] = sqrt(dis[i]);
avg += dis[i] / (n + 1);
}
for (int i = 1; i <= n + 1; ++i) {
for (int j = 1; j <= n; ++j) {
delta[j] += (dis[i] - avg) * (a[i][j] - ans[j]) / avg;
}
}
}
void solve() {
cin >> n;
for (int i = 1; i <= n + 1; ++i) {
for (int j = 1; j <= n; ++j) {
cin >> a[i][j];
ans[j] += a[i][j] / (n + 1);
}
}
for (double t = 1e4; t > 1e-4; t *= 0.99995) {
calc();
for (int i = 1; i <= n; ++i) ans[i] += delta[i] * t;
}
for (int i = 1; i <= n; ++i) cout << setiosflags(ios::fixed) << setprecision(3) << ans[i] << " ";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _t;
_t = 1;
//cin>>_t;
while (_t--) {
solve();
}
return 0;
}