2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)
D
题意:有 n 个人,每个人有 k 个特征,每个特征值为 0或 1。 定义两人的相似度为:k 个特征值中相同的个数。 要你另外找一个人,这个人和其他人相似度的最大值要尽可能小。
tags:bfs,思维
找一个人与其他人相似度的最大值尽可能小,也就是这个人与其他人 不相似度的最小值要尽可能大。
那我们可把这 n 个人当成 n 个点,总共有 (1<<k) 个点。我们以这 n 个点为起点 bfs,每走一步改变一个特征值,即 不相似度 +1 。最后找 不相似度最大的就是了。
// D #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 2000005; int n, k, dis[N]; char str[N]; queue< int > q; void bfs() { int u, to; while(!q.empty()) { u = q.front(); q.pop(); rep(j,1,k) { to = u^(1<<(j-1)); if(dis[to]==-1) { dis[to] = dis[u]+1; q.push(to); } } } } int main() { scanf("%d%d", &n, &k); mes(dis, -1); rep(i,1,n) { scanf("%s", str+1); int tmp = 0; rep(j,1,k) if(str[j]=='1') tmp+=1<<(j-1); dis[tmp]=0; q.push(tmp); } bfs(); int ans1, ans2=0; rep(i,0,(1<<k)-1) if(dis[i]>=ans2) ans1=i, ans2=dis[i]; rep(j,1,k) if((ans1>>(j-1))&1) putchar('1'); else putchar('0'); return 0; }
E
题意:n*m 的地方,每个地方给出高度,所有 n*m 的地方有海拔为 0 的积水。 现在给出一个点作为排水口,每个地方的水可以往周围八个方向,且比它低的地方流。问最后会流走多少水。
tags:bfs 跑一遍,同时要记录每个点可以下降到的最低点,且优生走更低的点。
// E #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 505; int n, m, a[N][N], ans[N][N]; struct Node { int x, y, h; bool friend operator<(Node a, Node b) { return a.h > b.h; } }; int dirx[8] = {1, -1, 0, 0, 1, 1, -1, -1}; int diry[8] = {0, 0, 1, -1, 1, -1, -1, 1}; priority_queue< Node > q; bool check(int x, int y) { return x>0 && x<=n && y>0 && y<=m; } void bfs(int x, int y, int h) { Node u; q.push((Node){ x,y,h }); int tx, ty; while(!q.empty()) { u = q.top(); q.pop(); x=u.x, y=u.y, h=u.h; if(ans[x][y]<h) continue; rep(i,0,7) { tx=x+dirx[i], ty=y+diry[i]; if(check(tx,ty) && max(a[tx][ty],h)<0 && ans[tx][ty]>max(a[tx][ty],h)) { ans[tx][ty] = max(h, a[tx][ty]); q.push((Node){ tx,ty,ans[tx][ty] }); } } } } int main() { scanf("%d%d", &n, &m); rep(i,1,n) rep(j,1,m) scanf("%d", &a[i][j]); int tx, ty; scanf("%d%d", &tx, &ty); ans[tx][ty]=min(0, a[tx][ty]); bfs(tx, ty, a[tx][ty]); ll ans1 = 0; rep(i,1,n) rep(j,1,m) if(ans[i][j]<0) ans1 += -ans[i][j]; printf("%lld ", ans1); return 0; }
I
题意: n 个文件,每个文件可以调用多个其它的文件,问最小的循环调用,且输出路径。 也就是在 DAG 图中找一个最小环。
tags:套板子-_-
Floyd 有向图找最小环
// Floyd 找有向图最小环 const int N = 505; int G[N][N], n ,m, dist[N][N], past[N][N]; int mincircle, path[N], cnt; void Init_Floyd() { for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) G[i][j] = INF; } void Floyd() { mincircle = INF; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) dist[i][j] = G[i][j], past[i][j] = i; for(int k = 1; k <= n; k++) //每个点都成为一次中间点,但和bellman-ford不一样 { for(int i = 1; i <= n; i++) //判断是不是最小环 for(int j = 1; j <= n; j++) { if(i == j) continue; if(dist[i][j]!=INF && G[j][k]!=INF && G[k][i]!=INF && mincircle>dist[i][j]+G[j][k]+G[k][i]) { mincircle = dist[i][j]+G[j][k]+G[k][i]; cnt = 0; int p=j; while(p!=i) //逆向寻找前驱结点直到找到最前面的i,i->…->j { path[cnt++]=p; p=past[i][p]; } path[cnt++]=i; path[cnt++]=k; } } for(int i = 1; i <= n; i++) // 这里就是 Floyd算法 for(int j = 1; j <= n; j++) { if(i == k || j == k) continue; if(dist[i][k]!=INF && dist[k][j]!=INF && dist[i][j]>dist[i][k]+dist[k][j]) { dist[i][j] = dist[i][k]+dist[k][j]; past[i][j] = past[k][j]; } } } } void print_path() { if(mincircle==INF || mincircle<0) puts("-1"); else { for(int i=cnt-1; i>=0; --i) printf("%d ", path[i]); puts(""); } }
// I #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 505; int grap[N][N] , n , m; int dist[N][N]; int past[N][N]; int mincircle; int path[N] , k1 ; void Init_Floyd() { int i , j; for(i = 1; i <= n; i++) for(j = 1; j <= n; j++) grap[i][j] = INF; } void Floyd() { mincircle = INF; int i , j; for(i = 1; i <= n; i++) for(j = 1; j <= n; j++) { dist[i][j] = grap[i][j]; past[i][j] = i; } for(int k = 1; k <= n; k++) //每个点都成为一次中间点 , 和bellman-ford不一样 { for(i = 1; i <= n; i++) //判断是不是最小环 for(j = 1; j <= n; j++) { //if(i == j) continue; if(dist[i][j]!=INF && grap[j][k]!=INF && grap[k][i]!=INF && mincircle>dist[i][j]+grap[j][k]+grap[k][i]) { mincircle = dist[i][j]+grap[j][k]+grap[k][i]; k1 = 0; int p=j; while(p!=i) //逆向寻找前驱结点直到找到最前面的i,i->…->j { path[k1++]=p; p=past[i][p];//fa[i][j]保存的不是k,而是fa[k][j]. } path[k1++]=i; path[k1++]=k; } } for(i = 1; i <= n; i++) //Floyd算法 for(j = 1; j <= n; j++) { //if(i == k || j == k) continue; if(dist[i][k]!=INF && dist[k][j]!=INF && dist[i][j]>dist[i][k]+dist[k][j]) { dist[i][j] = dist[i][k]+dist[k][j]; past[i][j] = past[k][j]; } } } } string str; char si[N]; map<string , int > mp; map<int , string > mp2; int main() { scanf("%d", &n); Init_Floyd(); rep(i,1,n) { scanf("%s", si); str = si; mp[str]=i, mp2[i]=str; } int k, u, len, to; bool flag; rep(i,1,n) { scanf("%s%d", si, &k); str = si; u = mp[str]; rep(j,1,k) { scanf("%s", si); while(~scanf("%s", si)) { flag = false; len = strlen(si); if(si[len-1]==',') { flag=true; si[len-1]='