// 7.19-7.29 东北大学秦皇岛校区十天训练营,题目都挂在了Vjudge上。训练期间比较忙,没空更博总结,回来继续补题消化。
// https://vjudge.net/contest/312902
https://vjudge.net/contest/313217
https://vjudge.net/contest/313584
https://vjudge.net/contest/314412
https://vjudge.net/contest/314730
https://vjudge.net/contest/314974
Day1
这天授课主题是简单图论,节奏挺好,wls两小时理完图论里的基本知识点。
下午的赛题就偏入门了(简单图论无疑),只涉及到最短路问题和简单的搜索以及一些奇怪的技巧。(差分约束呢?最小生成树呢?强连通分量呢?)
A - Jzzhu and Cities (补)
把火车线路加上跑Dijkstra就好了,标记火车线路,相等时也要push。在最短路上的火车线路不能被取消,剩下的全部能取消。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; typedef long long ll; const int maxn = 200010; struct Edge { int to; bool istrain; ll w; Edge(int v, bool is, ll ww):to(v), istrain(is), w(ww){} bool operator<(const Edge& a)const { if(w==a.w) return istrain; // 非火车节点先更新 return w > a.w; } }; vector<Edge> G[maxn]; bool vis[maxn]; int d[maxn]; int Dijkstra() { memset(d, 0x3f, sizeof(d)); memset(vis, 0, sizeof(vis)); d[1] = 0; int res = 0; priority_queue<Edge> q; q.push(Edge(1, 0, 0)); while(!q.empty()) { Edge tmp = q.top(); q.pop(); int u = tmp.to; if(vis[u]) continue; vis[u] = 1; // d[u] = tmp.w; if(tmp.istrain) ++res; for(int i=0;i<G[u].size();i++) { int v = G[u][i].to; if(!vis[v] && d[v]>=d[u]+G[u][i].w) { d[v] = d[u] + G[u][i].w; q.push(Edge(v, G[u][i].istrain, d[v])); } } } return res; } int main() { int n, m, k; cin>>n>>m>>k; int u, v, w; for(int i=0;i<m;i++) { scanf("%d %d %d", &u, &v, &w); G[u].push_back(Edge(v, 0, w)); G[v].push_back(Edge(u, 0, w)); } for(int i=0;i<k;i++) { scanf("%d %d", &v, &w); G[1].push_back(Edge(v, 1, w)); // G[v].push_back(Edge(1, 1, w)); } printf("%d\n", k-Dijkstra()); return 0; }
BFS 注意打标记!!!(虽然只是3*100的地图也要爆内存!)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; int n, k, sx; char mp[3][110]; bool vis[3][110]; struct node { int x, y; node(int _x, int _y):x(_x), y(_y) {} }; bool check(int x, int y) { if(x<0 || x>2) return false; if(y>=n) return true; if(mp[x][y]==‘.‘) return true; return false; } bool bfs() { queue<node> q; q.push(node(sx, 0)); while(q.size()) { node now = q.front(); q.pop(); if(now.y>=n) { return true; } // printf("(%d,%d) -> ", now.x, now.y); int nx = now.x, ny = now.y+1; if(!check(nx, ny)) continue; // 向右走一步 for(int i=-1;i<=1;i++) { // 尝试三个方向移动 nx = now.x + i; if(check(nx, ny) && check(nx, ny+1) && check(nx, ny+2) && !vis[nx][ny+2]) { q.push(node(nx, ny+2)); vis[nx][ny+2] = 1; } } } return false; } int main() { int t; cin>>t; while(t--) { scanf("%d %d", &n, &k); getchar(); memset(vis, 0, sizeof(vis)); for(int i=0;i<3;i++) { scanf("%s", mp[i]); if(mp[i][0]==‘s‘) sx = i; } printf("%s\n", bfs()?"YES":"NO"); } return 0; }
C - A Mist of Florescence (补)
构造题,技巧就是设计井字形的连通块,把其他颜色块涂到井字的格子上。
#include<iostream> #include<cstdio> using namespace std; int a, b, c, d; char ans[50][50]; void solve() { for(int i=1;i<=12;i++) { for(int j=1;j<50;j++) { if(i%2==1 && j%2==1 && a) ans[i][j] = ‘A‘, --a; else ans[i][j] = ‘D‘; } } for(int i=13;i<=24;i++) { for(int j=1;j<50;j++) { if(i%2==1 && j%2==1 && b) ans[i][j] = ‘B‘, --b; else ans[i][j] = ‘D‘; } } --c; --d; for(int i=25;i<=36;i++) { for(int j=1;j<50;j++) { if(i%2==1 && j%2==1 && c) ans[i][j] = ‘C‘, --c; else ans[i][j] = ‘D‘; } } for(int j=1;j<50;j++) { ans[37][j] = ‘C‘; } for(int i=38;i<50;i++) { for(int j=1;j<50;j++) { if(i%2==1 && j%2==1 && d) ans[i][j] = ‘D‘, --d; else ans[i][j] = ‘C‘; } } } int main() { cin>>a>>b>>c>>d; solve(); printf("49 49\n"); for(int i=1;i<50;i++) { for(int j=1;j<50;j++) printf("%c", ans[i][j]); printf("\n"); } return 0; }
DFS到墙的边界 对每块编号!
#include<iostream> #include<cstdio> using namespace std; int n, m, k; char mp[1010][1010]; int v[1010][1010], id; // v[i][j]: mp[i][j]的分类编号 id: 当前编号 int res[1010*1010]; // res[id]: 第id块的答案 const int dx[] = {0, 0, 1, -1}; const int dy[] = {1, -1, 0, 0}; int ans; void dfs(int x, int y) { if(mp[x][y]==‘*‘) { ans++; return; } v[x][y] = id; for(int i=0;i<4;i++) { int nx = x+dx[i], ny = y+dy[i]; if(nx>=0 && nx<m && ny>=0 && ny<n && !v[nx][ny]) { dfs(nx, ny); } } } int main() { scanf("%d %d %d", &m, &n, &k); getchar(); for(int i=0;i<m;i++) { scanf("%s", mp[i]); } for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { if(mp[i][j]==‘.‘ && !v[i][j]) { ++id; ans = 0; dfs(i, j); res[id] = ans; } } } while(k--) { int x, y; scanf("%d %d", &x, &y); printf("%d\n", res[v[x-1][y-1]]); } return 0; }
F - The Cild and Toy (补)
贪心!由于每去掉一个点,等价于去掉了所有与它相连的边,就是问去掉全部边的最小代价。答案当然就是每条边两个节点权值小的那头的总和。都不用建图!!
#include<iostream> #include<cstdio> using namespace std; const int maxn = 1010; int n, m; int w[maxn]; int main() { cin>>n>>m; for(int i=1;i<=n;i++) { scanf("%d", &w[i]); } int u, v, ans = 0; for(int i=0;i<m;i++) { scanf("%d %d", &u, &v); ans += min(w[u], w[v]); } printf("%d\n", ans); return 0; }
对连通部分排序就完事了
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; int n, num[310], id; int mp[310][310]; bool vis[310]; int ans[310]; struct list { vector<int> num; vector<int> id; }L[310]; void dfs(int x, int id) { vis[x] = 1; L[id].num.push_back(num[x]); L[id].id.push_back(x); for(int i=1;i<=n;i++) { if(mp[x][i]) { if(!vis[i]) dfs(i, id); } } } int main() { cin>>n; for(int i=1;i<=n;i++) { scanf("%d", &num[i]); } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { scanf("%1d", &mp[i][j]); } } for(int i=1;i<=n;i++) { if(!vis[i]) dfs(i, ++id); } for(int i=1;i<=id;i++) { // for(int j=0;j<L[i].num.size();j++) { // printf("%d:%d ", L[i].num[j], L[i].id[j]); // } // cout<<endl; sort(L[i].num.begin(), L[i].num.end()); sort(L[i].id.begin(), L[i].id.end()); for(int j=0;j<L[i].num.size();j++) { ans[L[i].id[j]] = L[i].num[j]; } } for(int i=1;i<=n;i++) { printf("%d%c", ans[i], i!=n?‘ ‘:‘\n‘); } return 0; }
H - Alyona and the Tree (补)
从根开始dfs就好,每个节点为max(0LL, now+w[i])
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> using namespace std; const int maxn = 100010; typedef long long ll; struct Edge { int to; ll w; Edge(int v, ll ww):to(v), w(ww) {} }; vector<Edge> G[maxn]; int n, vw[maxn]; int ans; void dfs(int u, int fa, ll now) { for(int i=0;i<G[u].size();i++) { int v = G[u][i].to; if(v!=fa) { if(vw[v]>=now+G[u][i].w) { --ans; // printf("%d->%d\n", u, v); dfs(v, u, max(now+G[u][i].w, 0LL)); } } } } int main() { cin>>n; ans = n; for(int i=1;i<=n;i++) { scanf("%d", &vw[i]); } int u, w; for(int i=2;i<=n;i++) { scanf("%d %d", &u, &w); G[i].push_back(Edge(u, w)); G[u].push_back(Edge(i, w)); } dfs(1, -1, 0); printf("%d\n", ans-1); return 0; }
L - Love Triangle
假的三元环??
#include <iostream> #include <cstdio> #include <algorithm> #include <vector> using namespace std; const int maxn = 5010; int n, tot; int love[maxn], low[maxn]; bool vis[maxn]; bool ans; void dfs(int u) { if(ans) return; vis[u] = true; low[u] = ++tot; int v = love[u]; if(v && !vis[v]) { dfs(v); if(love[v] && low[love[v]]==low[u]+2 && love[love[v]]==u) { ans = true; return; } } } int main() { cin>>n; for(int i=1;i<=n;i++) { scanf("%d", &love[i]); } ans = false; for(int i=1;i<=n;i++) { if(!vis[i] && !ans) dfs(i); } printf("%s\n", ans?"YES":"NO"); return 0; }
并查集
#include <iostream> #include <cstdio> using namespace std; const int maxn = 500100; int n, m; int fa[maxn]; int g[maxn], cnt[maxn]; int Find(int x) { return fa[x]==x?x:(fa[x]=Find(fa[x])); } void Union(int x, int y) { int a = Find(x); int b = Find(y); if(a==b) return; fa[a] = b; } int main() { cin>>n>>m; for(int i=1;i<=n;i++) fa[i] = i; while(m--) { int k; scanf("%d", &k); for(int i=0;i<k;i++) { scanf("%d", &g[i]); } for(int i=1;i<k;i++) { Union(g[0], g[i]); } } for(int i=1;i<=n;i++) { cnt[Find(i)]++; } for(int i=1;i<=n;i++) { printf("%d%c", cnt[Find(i)], i!=n?‘ ‘:‘\n‘); } return 0; }
O - NP-Hard Problem (补)
二分图裸题。。。
#include<iostream> #include<cstdio> #include<vector> using namespace std; typedef long long ll; const int maxn = 100010; int n, m; vector<int> G[maxn]; int deg[maxn]; int id[maxn]; vector<int> ans[2]; bool dfs(int u) { for(int i=0;i<G[u].size();i++) { int v = G[u][i]; if(!id[v]) { id[v] = 3 - id[u]; if(id[v]==1) ans[0].push_back(v); else ans[1].push_back(v); if(!dfs(v)) return false; } else if(id[v]==id[u]) return false; } return true; } int main() { cin>>n>>m; int u, v; for(int i=0;i<m;i++) { scanf("%d %d", &u, &v); G[u].push_back(v); G[v].push_back(u); ++deg[u]; } for(int i=1;i<=n;i++) { if(!deg[i]) continue; if(!id[i]) { id[i] = 1; ans[0].push_back(i); if(!dfs(i)) return 0 * printf("-1\n"); } } for(int k=0;k<=1;k++) { printf("%d\n", ans[k].size()); for(int i=0;i<ans[k].size();i++) { printf("%d%c", ans[k][i], i==ans[k].size()-1?‘\n‘:‘ ‘); } } return 0; }
Day2
Day3
Day4
Day5
Day6
原文地址:https://www.cnblogs.com/izcat/p/11274543.html