Graph Problems
Relocation (Luogu 3044)
Dijkstra + State Compression DP
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <bitset>
using namespace std;
const int maxn = 10005;
const int maxm = 50005;
const int maxk = 6;
const int inf = 0x7f7f7f7f;
int N, M, K;
int x, y, w;
int mkt[maxk];
struct edge {
int f, t, w;
edge() {}
edge(int f, int t, int w) :f(f), t(t), w(w) {}
};
vector<edge> G[maxn];
void insert_edge(int x, int y, int w) {
G[x].push_back(edge(x, y, w));
G[y].push_back(edge(y, x, w));
}
int dist[maxk][maxn];
#define P pair<int,int>
void dijkstra(int s, int k) {
int* d = dist[k];
priority_queue<P, vector<P>, greater<P>> q;
q.push(P(0, s));
d[s] = 0;
while (!q.empty()) {
P p = q.top(); q.pop();
int u = p.second;
if (d[u] < p.first) continue;
for (int i = 0; i < G[u].size(); i++) {
edge& e = G[u][i];
int v = e.t;
if (d[v] > d[u] + e.w) {
d[v] = d[u] + e.w;
q.push(P(d[v], v));
}
}
}
}
int dp[(1<<maxk) + 1][maxk + 1]; // state, last_choosen
int main() {
cin >> N >> M >> K;
for (int i = 0; i < K; i++) cin >> mkt[i];
for (int i = 0; i < M; i++) {
cin >> x >> y >> w;
insert_edge(x, y, w);
}
memset(dist, 0x3f, sizeof(dist));
for (int k = 0; k < K; k++) dijkstra(mkt[k], k);
int mxSt = (1 << K) - 1;
int ans = inf;
for (int i = 1; i <= N; i++) {
bool flag = false;
for (int k = 0; k < K; k++) if (mkt[k] == i) flag = true;
if (flag) continue;
//cout << "enumerate city " << i << endl;
memset(dp, 0x3f, sizeof(dp));
for (int k = 0; k < K; k++) dp[1<<k][k] = dist[k][i];
for (int st = 0; st < mxSt; st++) {
// enumerate possilbe last choosen city j
for (int j = 0; j < K; j++) {
if ((st >> j) & 1) {
// enumerate next choosen city k
for (int k = 0; k < K; k++) {
if (!((st >> k) & 1)) {
int newSt = st | (1 << k);
dp[newSt][k] = min(dp[newSt][k], dp[st][j] + dist[j][mkt[k]]);
//cout << "dp " <<bitset<8>(st)<<" "<<j<< " -> "<< bitset<8>(newSt) << " " << k << " = " << dp[newSt][k] << endl;
}
}
}
}
}
for (int k = 0; k < K; k++) ans = min(ans, dp[mxSt][k] + dist[k][i]);
}
cout << ans << endl;
}
Full Tank ?
太难了,本质DP,Dijkstra可以操作二维数组。
#include <cstdio>
#include <cstring>
#include <queue>
#define rep(i,j,k) for(i=j;i<k;i++)
using namespace std;
const int N = 1001, M = 20001, inf = 0x7f7f7f7f;
int h[N], p[M], v[M], w[M], c[N], cnt = 0;
int dp[N][101], vis[N][101], s, t, cap;
struct Data {
int x, o, c;
Data() {}
Data(int x, int o, int c) :x(x), o(o), c(c) {}
};
bool operator <(Data a, Data b) { return a.c > b.c; }
void add(int x, int y, int z) {
p[++cnt] = h[x]; w[cnt] = z; v[cnt] = y; h[x] = cnt;
}
int dij() {
priority_queue<Data> q;
memset(dp, 127, sizeof dp);
memset(vis, 0, sizeof vis);
dp[s][0] = 0;
q.push(Data(s, 0, 0));
while (!q.empty()) {
Data u = q.top(); q.pop();
vis[u.x][u.o] = 1;
if (u.x == t) return u.c;
if (u.o < cap && !vis[u.x][u.o + 1] &&
dp[u.x][u.o + 1] > dp[u.x][u.o] + c[u.x]) {
dp[u.x][u.o + 1] = dp[u.x][u.o] + c[u.x];
q.push(Data(u.x, u.o + 1, dp[u.x][u.o + 1]));
}
for (int i = h[u.x]; i; i = p[i])
if (u.o >= w[i] && !vis[v[i]][u.o - w[i]] &&
dp[v[i]][u.o - w[i]] > dp[u.x][u.o]) {
dp[v[i]][u.o - w[i]] = dp[u.x][u.o];
q.push(Data(v[i], u.o - w[i], dp[v[i]][u.o - w[i]]));
}
}
return -1;
}
int main() {
int n, i, m, q;
scanf("%d%d", &n, &m);
rep(i, 0, n) scanf("%d", c + i);
while (m--) {
scanf("%d%d%d", &s, &t, &cap);
add(s, t, cap); add(t, s, cap);
}
scanf("%d", &q);
while (q--) {
scanf("%d%d%d", &cap, &s, &t);
int re = dij();
if (re == -1) puts("impossible");
else printf("%d\n", re);
}
return 0;
}
道路
类似上题。
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 105;
const int maxr = 10005;
const int maxk = 10005;
const int inf = 0x3f3f3f3f;
int N, K, R;
struct edge {
int f, t, l, c;
edge() {}
edge(int f, int t, int l, int c) :f(f), t(t), l(l), c(c) {}
};
vector<edge> G[maxn];
void insert_edge(int f, int t, int l, int c) {
G[f].push_back(edge(f, t, l, c));
//G[t].push_back(edge(t, f, l, c));
}
int dist[maxn][maxk];
struct node {
int pos, cost, dist;
node() {}
node(int p, int c, int d) :pos(p), cost(c), dist(d) {}
bool operator < (const node& b) const {
return dist > b.dist;
}
};
void dijkstra() {
memset(dist, 0x3f, sizeof(dist));
dist[1][0] = 0;
priority_queue<node> q;
q.push(node(1, 0, 0));
while (!q.empty()) {
node p = q.top(); q.pop();
if (p.dist != dist[p.pos][p.cost]) continue;
for (int i = 0; i < G[p.pos].size(); i++) {
edge& e = G[p.pos][i];
if (p.cost+e.c <= K && dist[e.t][p.cost+e.c] > dist[p.pos][p.cost] + e.l) {
dist[e.t][p.cost+e.c] = dist[p.pos][p.cost] + e.l;
q.push(node(e.t, p.cost + e.c, dist[e.t][p.cost+e.c]));
}
}
}
}
int f, t, l, c;
int main() {
cin >> K >> N >> R;
for (int i = 0; i < R; i++) {
cin >> f >> t >> l >> c;
insert_edge(f, t, l, c);
}
dijkstra();
int ans = inf;
for (int k = 0; k <= K; k++) ans = min(ans, dist[N][k]);
cout << (ans == inf ? -1 : ans) << endl;
}
Window Pains
Topo sort to find Directed Loops. 有向图判圈,就用拓扑排序!此外此题如何构图也比较困难。
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 10;
int N = 9;
int G[maxn][maxn];
int mat[4][4];
void insert_edge(int a, int b) {
G[a][b] = 1;
}
void build() {
memset(G, 0, sizeof(G));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int val = i * 3 + j + 1;
if (mat[i][j] != val) insert_edge(val, mat[i][j]);
if (mat[i][j+1] != val) insert_edge(val, mat[i][j+1]);
if (mat[i+1][j] != val) insert_edge(val, mat[i+1][j]);
if (mat[i+1][j+1] != val) insert_edge(val, mat[i+1][j+1]);
}
}
}
int vis[maxn];
int ind[maxn];
bool checkloop() {
memset(vis, 0, sizeof(vis));
memset(ind, 0, sizeof(ind));
// calc ind[]
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++)
if (G[i][j]) ind[j]++;
// bfs
queue<int> q;
for (int i = 1; i <= N; i++) if (ind[i] == 0) q.push(i);
while (!q.empty()) {
int p = q.front(); q.pop();
vis[p] = 1;
for (int i = 1; i <= N; i++) {
if (G[p][i]) {
if (--ind[i] == 0) q.push(i);
}
}
}
// check unvisited points (loops)
for (int i = 1; i <= N; i++) if (!vis[i]) return true;
return false;
}
string s;
int main() {
while (cin >> s) {
if (s == "START") {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
cin >> mat[i][j];
}
}
build();
if (checkloop()) cout << "THESE WINDOWS ARE BROKEN" << endl;
else cout << "THESE WINDOWS ARE CLEAN" << endl;
}
else if (s == "END") continue;
else if (s == "ENDOFINPUT") break;
}
}