2016长乐夏令营 Day12

来源:互联网 发布:熊猫tv怎么刷猫币淘宝 编辑:程序博客网 时间:2024/04/29 23:18

T1:

f[i][j]:吃掉的黑子状态为i,当前在第j个棋子的位置上,走的最小步数

因为棋盘是不断更新的,所以每个状态要更新后续状态的时候要一遍BFS

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<stack>#include<cstdlib>#include<cmath>#include<algorithm>#include<bitset>using namespace std;const int maxn = 20;const int maxm = 1<<15;const int INF = ~0U>>1;const int dx[8] = {0,1,0,-1,1,1,-1,-1};const int dy[8] = {1,0,-1,0,1,-1,1,-1};const int kx[8] = {2,2,1,1,-1,-1,-2,-2};const int ky[8] = {1,-1,2,-2,2,-2,1,-1};struct P{int A,B;P(int _A = 0,int _B = 0) {A = _A; B = _B;}};struct Point{int x,y;Point(int _x = 0,int _y = 0) {x = _x; y = _y;}};int n,m,tot,pox[maxn],poy[maxn],f[maxm][16],Mark[maxn][maxn],num[maxn][maxn],cnt,vis[maxn][maxn],dis[maxn][maxn],B[maxn],typ[maxn];char p[maxn][maxn];bool inq[maxm][16]; queue <P> Q1;queue <Point> Q2;void Work(int tx,int ty,int l){for (;;) {tx += dx[l]; ty += dy[l];if (tx < 0 || tx == n || ty < 0 || ty == m) return;Mark[tx][ty] = cnt;if (B[num[tx][ty]] != cnt) return;}}void Mark1(int qx,int qy){for (int i = 0; i < 8; i++) {int xx = qx + kx[i];int yy = qy + ky[i];if (xx < 0 || xx >= n || yy < 0 || yy >= m) continue;Mark[xx][yy] = cnt;}}void Mark2(int qx,int qy){for (int i = 4; i < 8; i++)Work(qx,qy,i);}void Mark3(int qx,int qy){for (int i = 0; i < 4; i++)Work(qx,qy,i);}void BFS(int now,int px,int py){int nx = now; B[0] = cnt;for (int i = 1; i <= tot; i++) {if (nx&1) B[i] = cnt;nx >>= 1;} nx = now;for (int i = 1; i <= tot; i++) {if (!(nx&1)) {if (typ[i] == 1) Mark1(pox[i],poy[i]);if (typ[i] == 2) Mark2(pox[i],poy[i]);if (typ[i] == 3) Mark3(pox[i],poy[i]);}nx >>= 1; }vis[px][py] = cnt; dis[px][py] = 0;Q2.push(Point(px,py));while (!Q2.empty()) {Point k = Q2.front(); Q2.pop();for (int i = 0; i < 8; i++) {int xx = k.x + dx[i];int yy = k.y + dy[i];if (xx < 0 || xx == n || yy < 0 || yy == m) continue;if (vis[xx][yy] == cnt || Mark[xx][yy] == cnt) continue;vis[xx][yy] = cnt; dis[xx][yy] = dis[k.x][k.y] + 1;Q2.push(Point(xx,yy));}}}int main(){#ifdef DMCfreopen("DMC.txt","r",stdin);    #elsefreopen("chess.in","r",stdin);freopen("chess.out","w",stdout);#endifcin >> n >> m;for (int i = 0; i < n; i++) {scanf("%s",p[i]);for (int j = 0; j < m; j++)if (p[i][j] != '.') {if (p[i][j] == '*') {pox[0] = i; poy[0] = j;continue;}++tot; pox[tot] = i; poy[tot] = j;num[i][j] = tot;if (p[i][j] == 'K') typ[tot] = 1;if (p[i][j] == 'B') typ[tot] = 2;if (p[i][j] == 'R') typ[tot] = 3;}}if (!tot) {cout << 0; return 0;}for (int i = 0; i < (1<<tot); i++)for (int j = 0; j <= tot; j++)f[i][j] = INF;Q1.push(P(0,0)); f[0][0] = 0; inq[0][0] = 1;while (!Q1.empty()) {P k = Q1.front(); Q1.pop();++cnt; BFS(k.A,pox[k.B],poy[k.B]);int now = k.A;for (int pos = 1; pos <= tot; pos++,now >>= 1) {if (!(now&1)) {int Next = k.A|(1<<(pos-1));if (vis[pox[pos]][poy[pos]] != cnt) continue;if (f[Next][pos] > f[k.A][k.B] + dis[pox[pos]][poy[pos]]) {f[Next][pos] = f[k.A][k.B] + dis[pox[pos]][poy[pos]];if (!inq[Next][pos]) Q1.push(P(Next,pos)),inq[Next][pos] = 1;}}}}int ans = INF;for (int i = 0; i <= tot; i++)ans = min(ans,f[(1<<tot)-1][i]);if (ans == INF) cout << -1;else cout << ans; return 0;}


T2:

首先,,是棵斯坦纳树不会错

但是,题目只是要求每户人家能进一个屋子

所以,我们只要求出一些连通块使得能配出k对就好

f[i][j]:关键点连通情况为i,当前根为j的斯坦纳树

g[i]:关键点配对情况为i的最优方案

对于g,g的初值不能由f直接转移,要f中状态恰好两两配对的才能赋为初值

斯坦纳树+dp,方程不再赘述

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<stack>#include<cstdlib>#include<cmath>#include<algorithm>#include<bitset>using namespace std;const int maxn = 55;const int maxm = 1<<11;const int INF = 1E9;struct E{int to,w;E(int _to = 0,int _w = 0) {to = _to; w = _w;}};int n,m,k,T,f[maxm][maxn],g[maxm],vis[maxn];vector <E> v[maxn];queue <int> Q;void SPFA(int o){while (!Q.empty()) {int K = Q.front(); Q.pop(); vis[K] = 0;for (int i = 0; i < v[K].size(); i++) {int to = v[K][i].to;if (f[o][to] > f[o][K] + v[K][i].w) {f[o][to] = f[o][K] + v[K][i].w;if (!vis[to]) vis[to] = 1,Q.push(to);}}}}bool check(int o){int K = k/2,tot = 0;for (int i = 0; i < K; i++) {if (o&1) ++tot;o >>= 1;}for (int i = 0; i < K; i++) {if (o&1) --tot;o >>= 1;}return !tot;}int main(){#ifdef DMCfreopen("DMC.txt","r",stdin);    #elsefreopen("spring.in","r",stdin);freopen("spring.out","w",stdout);#endifcin >> T;while (T--) {scanf("%d%d%d",&n,&m,&k);while (m--) {int x,y,z; scanf("%d%d%d",&x,&y,&z);v[x].push_back(E(y,z));v[y].push_back(E(x,z));}int pos = n - k + 1; k <<= 1;for (int i = 0; i < (1<<k); i++)for (int j = 1; j <= n; j++)f[i][j] = INF;for (int i = 1; i <= k/2; i++) f[1<<(i-1)][i] = 0;for (int i = k/2 + 1; i <= k; i++) f[1<<(i-1)][pos] = 0,++pos;for (int o = 0; o < (1<<k); o++) {for (int i = 1; i <= n; i++) {for (int op = (o - 1) & o; op; op = (op - 1) & o) f[o][i] = min(f[o][i],f[op][i] + f[o - op][i]);if (f[o][i] != INF) Q.push(i),vis[i] = 1;}SPFA(o);}for (int i = 0; i < (1<<k); i++) {g[i] = INF;if (check(i)) for (int j = 1; j <= n; j++)g[i] = min(g[i],f[i][j]);}for (int o = 0; o < (1<<k); o++)for (int op = (o - 1) & o; op; op = (op - 1) & o)g[o] = min(g[o],g[op] + g[o - op]);if (g[(1<<k) - 1] != INF) printf("%d\n",g[(1<<k) - 1]);else printf("No solution\n"); for (int i = 1; i <= n; i++) v[i].clear();}return 0;}

T3:

行和列的变换不受顺序影响,单个变换可以留到最后

行和列的变换方式为4!*4!种,枚举出来,快速判断单个的变换就好

写的时候居然dfs行列变换,,,我简直傻逼

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<stack>#include<cstdlib>#include<cmath>#include<algorithm>#include<bitset>using namespace std;int ans = 16,cnt,a[10][10],bx[10],by[10],nx[10],ny[10],tx[10],ty[10],b[10][10],bo[20],sx[20],sy[20];int QuickJudge(){int ret,sum; ++cnt; ret = 0;for (int i = 1; i <= 4; i++)for (int j = 1; j <= 4; j++)if (sx[b[i][j]] != i || sy[b[i][j]] != j) {if (bo[b[i][j]] == cnt) continue;int now = b[i][j]; sum = 0;for (;;) {++sum; bo[now] = cnt;int xx = sx[now];int yy = sy[now];now = b[xx][yy];if (now == b[i][j]) break;}ret += (sum - 1);}return ret;}int getint(){int ret = 0;char ch = getchar();while (ch < '0' || '9' < ch) ch = getint();while ('0' <= ch && ch <= '9')ret = ret*10 + ch - '0',ch = getchar();return ret;}void Judge(){int tot = 0; ++cnt;for (int i = 1; i <= 4; i++) {int sum = 0;if (tx[nx[i]] != cnt) {int now = nx[i];for (;;) {++sum; tx[now] = cnt;now = nx[now];if (now == nx[i]) break;}tot += (sum-1);} sum = 0;if (ty[ny[i]] != cnt) {int now = ny[i];for (;;) {++sum; ty[now] = cnt;now = ny[now];if (now == ny[i]) break;}tot += (sum-1);}}for (int i = 1; i <= 4; i++)for (int j = 1; j <= 4; j++)b[i][j] = a[nx[i]][ny[j]];tot += QuickJudge();ans = min(ans,tot);}void dfs2(int y){if (y == 5) {Judge(); return;}for (int i = 1; i <= 4; i++) if (!by[i]) {by[i] = 1; ny[y] = i;dfs2(y+1);by[i] = 0;}}void dfs1(int x){if (x == 5) {dfs2(1); return;}for (int i = 1; i <= 4; i++) if (!bx[i]) {bx[i] = 1; nx[x] = i;dfs1(x+1);bx[i] = 0;}}int main(){#ifdef DMCfreopen("DMC.txt","r",stdin);    #elsefreopen("puzzle.in","r",stdin);freopen("puzzle.out","w",stdout);#endiffor (int i = 1; i <= 4; i++)for (int j = 1; j <= 4; j++)a[i][j] = getint();int X = 1,Y = 1;for (int i = 1; i <= 16; i++) {sx[i] = X; sy[i] = Y;++Y;if (Y > 4) ++X,Y = 1;}dfs1(1);cout << ans; return 0;}


0 0
原创粉丝点击