bupt summer training for 16 #6 ——图论
https://vjudge.net/contest/174020
A.100条双向边,每个点最少连2个边
所以最多100个点,点的标号需要离散化
然后要求恰好经过n条路径
快速幂,乘法过程就是floyed就行了
1 #include <algorithm> 2 #include <cstring> 3 #include <cstdio> 4 5 using namespace std; 6 7 const int maxn = 1010; 8 9 int n, m, s, t, b, c[1001]; 10 11 struct matrix { 12 int c[101][101]; 13 matrix() { 14 memset(c, 0x3f, sizeof c); 15 } 16 void add(int u, int v, int w) { 17 c[u][v] = c[v][u] = w; 18 } 19 matrix operator * (const matrix &a) const { 20 matrix b; 21 for(int k = 1;k <= n;k ++) 22 for(int i = 1;i <= n;i ++) 23 for(int j = 1;j <= n;j ++) 24 b.c[i][j] = min(b.c[i][j], c[i][k] + a.c[k][j]); 25 return b; 26 } 27 matrix operator ^ (int &k) { 28 matrix b = *this; 29 for(k --;k > 0;k >>= 1, *this = (*this) * (*this)) 30 if(k & 1) b = b * (*this); 31 return b; 32 } 33 }; 34 35 int main() { 36 matrix g; 37 int u, v, w; 38 scanf("%d %d %d %d", &n, &m, &s, &t); 39 while(m --) { 40 scanf("%d %d %d", &w, &u, &v); 41 if(!c[u]) c[u] = ++ b; 42 if(!c[v]) c[v] = ++ b; 43 g.add(c[u], c[v], w); 44 } 45 swap(b, n); 46 printf("%d", (g ^ b).c[c[s]][c[t]]); 47 return 0; 48 }
B.
C.非常裸的生成树计数问题
其实谁是最高管理层并没什么卵用
想当然理解了读入,垃圾题目有重边
注意有重边,整数行列式计算可以拿来当板子了
1 #include <algorithm> 2 #include <cstring> 3 #include <cstdio> 4 5 using namespace std; 6 7 const int maxn = 1010; 8 9 int n, m, s, t, b, c[1001]; 10 11 struct matrix { 12 int c[101][101]; 13 matrix() { 14 memset(c, 0x3f, sizeof c); 15 } 16 matrix(int x) { 17 memset(c, 0, sizeof c); 18 for(int i = 1;i <= n;i ++) 19 c[i][i] = 1; 20 } 21 void add(int u, int v, int w) { 22 c[u][v] = c[v][u] = w; 23 } 24 matrix operator * (const matrix &a) const { 25 matrix b; 26 for(int k = 1;k <= n;k ++) 27 for(int i = 1;i <= n;i ++) 28 for(int j = 1;j <= n;j ++) 29 b.c[i][j] = min(b.c[i][j], c[i][k] + a.c[k][j]); 30 return b; 31 } 32 matrix operator ^ (int &k) { 33 matrix b = *this; 34 for(k --;k > 0;k >>= 1, *this = (*this) * (*this)) 35 if(k & 1) b = b * (*this); 36 return b; 37 } 38 }; 39 40 int main() { 41 matrix g; 42 int u, v, w; 43 scanf("%d %d %d %d", &n, &m, &s, &t); 44 while(m --) { 45 scanf("%d %d %d", &w, &u, &v); 46 if(!c[u]) c[u] = ++ b; 47 if(!c[v]) c[v] = ++ b; 48 g.add(c[u], c[v], w); 49 } 50 swap(b, n); 51 printf("%d", (g ^ b).c[c[s]][c[t]]); 52 return 0; 53 }
D.
E.高中做过的网络流模型
每行被隔开的算一块,st向这些块连边流量为1
因为这样一个块里最多放一个棋子
每列被隔开的算一块,这些块向en连边流量为1,道理同上
行块和列快相遇出可以放旗子,那么它们连一条边流量为1
因为只有一个位置
求个最大流...这样一说直接二分图上匈牙利就可以了...
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int maxn = 50010, maxm = 1000010, inf = 0x3f3f3f3f; 8 9 int s, t, len = 1, g[maxn]; 10 11 struct edge { 12 int to, cap, next; 13 }e[maxm]; 14 15 int p[maxn], q[maxn], d[maxn]; 16 17 void add(int u, int v, int w) { 18 e[++ len] = (edge){v, w, g[u]}, g[u] = len; 19 e[++ len] = (edge){u, 0, g[v]}, g[v] = len; 20 } 21 22 bool bfs() { 23 int l = 1, r = 1, x, i; 24 memset(d, 0, sizeof d); 25 d[s] = 1, q[1] = s; 26 while(l <= r) { 27 x = q[l ++]; 28 for(i = g[x];i;i = e[i].next) 29 if(e[i].cap && !d[e[i].to]) 30 d[e[i].to] = d[x] + 1, q[++ r] = e[i].to; 31 } 32 return d[t]; 33 } 34 35 int dfs(int x, int y) { 36 if(x == t || y == 0) return y; 37 int flow = 0; 38 for(int &i = p[x];i;i = e[i].next) { 39 if(!e[i].cap || d[e[i].to] != d[x] + 1) continue; 40 int f = dfs(e[i].to, min(y, e[i].cap)); 41 flow += f, y -= f; 42 e[i].cap -= f, e[i ^ 1].cap += f; 43 if(!y) break; 44 } 45 return flow; 46 } 47 48 int dinic() { 49 int maxflow = 0; 50 while(bfs()) { 51 memcpy(p, g, sizeof g); 52 maxflow += dfs(s, inf); 53 } 54 return maxflow; 55 } 56 57 int n, m, cnt; 58 59 char str[110][110]; 60 61 int mmp[110][110]; 62 63 int main() { 64 t = 10001; 65 while(~scanf("%d", &n)) { 66 m = 0; 67 memset(g, 0, sizeof g); 68 for(int i = 1;i <= n;i ++) 69 scanf("%s", str[i] + 1); 70 for(int i = 1;i <= n;i ++) { 71 for(int j = 1;j <= n;j ++) { 72 if(str[i][j] == 'X') mmp[i][j] = -1; 73 else { 74 if(j == 1 || str[i][j - 1] == 'X') m ++, add(s, m, 1); 75 mmp[i][j] = m; 76 } 77 } 78 } 79 for(int j = 1;j <= n;j ++) 80 for(int i = 1;i <= n;i ++) { 81 if(str[i][j] != 'X') { 82 if(i == 1 || str[i - 1][j] == 'X') m ++, add(m, t, 1); 83 add(mmp[i][j], m, inf); 84 } 85 } 86 printf("%d\n", dinic()); 87 } 88 }
F.裸的最短路,当然你要看到这是
单向边!!!
1 #include <queue> 2 #include <cstdio> 3 #include <vector> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int maxn = 1010; 9 10 queue <int> q; 11 12 int n, m, k, t, d[maxn], vis[maxn]; 13 14 vector <pair<int, int> > e[maxn]; 15 16 int main(){ 17 while(~scanf("%d %d %d", &n, &m, &k)) { 18 for(int i = 1;i <= n;i ++) d[i] = 0x3f3f3f3f, e[i].clear(); 19 for(int u, v, w, i = 1;i <= m;i ++) { 20 scanf("%d %d %d", &u, &v, &w); 21 e[u].push_back(make_pair(v, w)); 22 //e[v].push_back(make_pair(u, w)); 23 } 24 scanf("%d", &t); 25 for(int j, i = 1;i <= t;i ++) 26 scanf("%d", &j), d[j] = 0, q.push(j); 27 while(!q.empty()) { 28 int u = q.front(); 29 q.pop(), vis[u] = 0; 30 for(int i = 0;i < e[u].size();i ++) { 31 if(d[e[u][i].first] > d[u] + e[u][i].second) { 32 d[e[u][i].first] = d[u] + e[u][i].second; 33 if(!vis[e[u][i].first]) vis[e[u][i].first] = 1, q.push(e[u][i].first); 34 } 35 } 36 } 37 printf("%d\n", d[k] == 0x3f3f3f3f ? -1 : d[k]); 38 } 39 return 0; 40 }
G.裸MST,稠密图没有卡 Kruskal,良心!
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 struct edge { 7 int u, v, w; 8 bool operator < (const edge &a) const { 9 return w < a.w; 10 } 11 }e[10010]; 12 13 int n, f[110]; 14 15 int find_(int x) { 16 if(f[x] != x) return f[x] = find_(f[x]); 17 return x; 18 } 19 20 int main() { 21 while(~scanf("%d", &n)) { 22 int m = 0, ans = 0; 23 for(int k, i = 1;i <= n;i ++) { 24 f[i] = i; 25 for(int j = 1;j <= i;j ++) scanf("%d", &k); 26 for(int j = i + 1;j <= n;j ++) scanf("%d", &k), e[++ m] = (edge){i, j, k}; 27 } 28 sort(e + 1, e + m + 1); 29 for(int u, v, i = 1, j = 1;j < n;i ++) { 30 u = find_(e[i].u), v = find_(e[i].v); 31 if(u == v) continue; 32 f[v] = u, j ++, ans += e[i].w; 33 } 34 printf("%d\n", ans); 35 } 36 return 0; 37 }
H.
I.经典网络流模型
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int maxn = 110, maxm = 50010, inf = 0x3f3f3f3f; 8 9 int s, t, len = 1, g[maxn]; 10 11 struct edge { 12 int to, cap, next; 13 }e[maxm]; 14 15 int p[maxn], q[maxn], d[maxn]; 16 17 void add(int u, int v, int w) { 18 e[++ len] = (edge){v, w, g[u]}, g[u] = len; 19 e[++ len] = (edge){u, 0, g[v]}, g[v] = len; 20 } 21 22 bool bfs() { 23 int l = 1, r = 1, x, i; 24 memset(d, 0, sizeof d); 25 d[s] = 1, q[1] = s; 26 while(l <= r) { 27 x = q[l ++]; 28 for(i = g[x];i;i = e[i].next) 29 if(e[i].cap && !d[e[i].to]) 30 d[e[i].to] = d[x] + 1, q[++ r] = e[i].to; 31 } 32 return d[t]; 33 } 34 35 int dfs(int x, int y) { 36 if(x == t || y == 0) return y; 37 int flow = 0; 38 for(int &i = p[x];i;i = e[i].next) { 39 if(!e[i].cap || d[e[i].to] != d[x] + 1) continue; 40 int f = dfs(e[i].to, min(y, e[i].cap)); 41 flow += f, y -= f; 42 e[i].cap -= f, e[i ^ 1].cap += f; 43 if(!y) break; 44 } 45 return flow; 46 } 47 48 int dinic() { 49 int maxflow = 0; 50 while(bfs()) { 51 memcpy(p, g, sizeof g); 52 maxflow += dfs(s, inf); 53 } 54 return maxflow; 55 } 56 57 int Case, n, m, sum; 58 59 int main() { 60 scanf("%d", &Case); 61 for(int tt = 1;tt <= Case;tt ++) { 62 sum = 0, len = 1; 63 memset(g, 0, sizeof g); 64 printf("Case #%d: ", tt); 65 scanf("%d %d", &n, &m), t = n + m + 1; 66 for(int j, i = 1;i <= n;i ++) 67 scanf("%d", &j), add(s, i, j), sum += j; 68 for(int j, i = 1;i <= m;i ++) 69 scanf("%d", &j), add(n + i, t, j); 70 for(int k, j, i = 1;i <= n;i ++) { 71 scanf("%d", &k); 72 while(k --) { 73 scanf("%d", &j); 74 add(i, n + j + 1, inf); 75 } 76 } 77 for(int k, i = 1;i <= m;i ++) 78 for(int j = 1;j <= m;j ++) { 79 scanf("%d", &k); 80 if(k) add(n + i, n + j, inf); 81 } 82 printf("%d\n", sum - dinic()); 83 } 84 return 0; 85 }
J.随便做的傻逼题,我写的算麻烦的
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 6 int n, a[110]; 7 8 int main() { 9 scanf("%d", &n); 10 for(int i = 1;i <= n;i ++) 11 scanf("%d", &a[i]); 12 int l = 1, r = n; 13 while(!a[l] && l <= n) l ++; 14 while(!a[r] && r >= 1) r --; 15 if(l > r) puts("0"); 16 else { 17 int ans = 1, last = 1; 18 for(int i = l + 1;i <= r;i ++) { 19 if(a[i]) { 20 ans ++; 21 if(last != 1) last = 1; 22 } 23 else { 24 if(last != 0) { 25 if(i < r && !a[i + 1]) last = 0; 26 else ans ++; 27 } 28 } 29 } 30 printf("%d\n", ans); 31 } 32 return 0; 33 }