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 DMC
freopen("DMC.txt","r",stdin);
#else
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
#endif
cin >> 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 DMC
freopen("DMC.txt","r",stdin);
#else
freopen("spring.in","r",stdin);
freopen("spring.out","w",stdout);
#endif
cin >> 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 DMC
freopen("DMC.txt","r",stdin);
#else
freopen("puzzle.in","r",stdin);
freopen("puzzle.out","w",stdout);
#endif
for (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;
}