题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2595
题目大意:给你n*m的矩阵,每个格子上的数字表示该地的权值,权值为0,表示该点为关键点,现在让你求至少包含这些关键点的STNT,然后一种可行方案。
思路:STNT,就是加了输出路径。
这里还要注意,由于我们是把权值放在节点上,所以枚举子树做DP时,还要减掉一个 该点的权值,即 d[ s ][ i ] = min(d[ s ][ s1 ]+ d[ s2 ][ s - s1 ] - mat[ i ]),s1为s的子集。
inq[ s ][ i ] 一直写成 inq[ i ] ,调了好久,编译器还不报错。。 = =
还有边先开始只开了 MAXN*MAXN*2,竟然不报 RE,报 WA,这个调得更久,怪不得一直 WA 呢。。。T^T
代码如下:
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int INF = 0x0fffffff ;
const int MAXN = 11;
struct Edge
{
int t,next,w;
} edge[MAXN*MAXN*4];
int tot,head[MAXN*MAXN];
void add_edge(int s,int t,int w)
{
edge[tot].w = w;
edge[tot].t = t;
edge[tot].next = head[s];
head[s] = tot++;
}
char map[MAXN][MAXN];
int d[1<<11][MAXN*MAXN];
int val[MAXN*MAXN];
vector <int> spot;
bool inq[1<<11][MAXN*MAXN];
struct Node
{
int s,id;
Node(){}
Node(int a,int b) : s(a),id(b) {}
};
Node path[1<<11][MAXN*MAXN];
queue <Node> q;
void init(int n,int k)
{
int S = 1<<k;
for(int s = 0;s < S;s++)
for(int i = 0;i<n;i++)
d[s][i] = INF;
for(int i = 0;i<spot.size();i++)
{
int cur = spot[i];
d[val[cur]][cur] = 0;
path[val[cur]][cur].id = -1;
}
}
int update(int s,int id,int w,int from_s,int from_id)
{
if(d[s][id] > w)
{
d[s][id] = w;
path[s][id].s = from_s;
path[s][id].id = from_id;
return 1;
}
else return 0;
}
void spfa()
{
while(!q.empty())
{
int s = q.front().s;
int id = q.front().id;
inq[s][id] = 0;
q.pop();
for(int e = head[id]; e != -1;e = edge[e].next)
{
int v = edge[e].t;
int w = edge[e].w;
if(update(s|val[v],v,d[s][id] + w,s,id) && s|val[v] == s && !inq[s][v])
{
inq[s][v] = 1;
q.push(Node(s,v));
}
}
}
}
int p[MAXN*MAXN];
void stnt(int n,int k)
{
init(n,k);
int S = 1<<k;
for(int s = 1;s<S;s++)
{
for(int i = 0;i<n;i++)
{
if(val[i] && !(val[i]&s)) continue;
for(int s1 = (s - 1)&s ; s1 ;s1 = (s1 - 1)&s)
{
int s2 = s - s1;
int tmp = d[s1|val[i]][i] + d[s2|val[i]][i] - p[i] ;
if(d[s][i] > tmp)
{
d[s][i] = tmp;
path[s][i].s = s1|val[i];
path[s][i].id = i;
}
}
if(d[s][i] < INF) q.push(Node(s,i)),inq[s][i] = 1;
}
spfa();
//for(int i = 0;i<n;i++)
//printf("s = %d,i = %d,d = %d\n",s,i,d[s][i]);
}
}
void print(int s,int id,int n,int m)
{
if(val[id] == 0)
{
map[id/m][id%m] = 'o';
}
if(path[s][id].id == -1) return ;
if(path[s][id].id == id)
{
print(path[s][id].s ,id,n,m);
print((s - path[s][id].s)|val[id] ,id,n,m);//注意这里的状态转移
}
else
{
print(path[s][id].s,path[s][id].id,n,m);
}
}
int main()
{
//freopen("D://out.txt","w",stdout);
int n,m;
while(~scanf("%d%d",&n,&m))
{
tot=0;
memset(head,-1,sizeof(head));
int cc = 0;
spot.clear();
for(int i = 0;i<n;i++)
{
for(int j = 0;j<m;j++)
{
int cur = i*m+j;
val[cur] = 0;
int a;
scanf("%d",&a);
p[cur] = a;
if(i >= 1) add_edge(cur - m,cur,a);
if(i <= n - 2) add_edge(cur + m,cur,a);
if(j >= 1) add_edge(cur - 1,cur,a);
if(j <= m - 2) add_edge(cur + 1,cur,a);
if(a == 0)
{
map[i][j] = 'x';
val[cur] = 1<<cc;
spot.push_back(cur);
cc ++;
}
else map[i][j] = '_';
}
map[i][m] = '\0';
}
int nn = n*m;
stnt(nn,cc);
int S = 1<<cc;
int x;
int minn = INF;
for(int i =0;i<nn;i++)
if(d[S - 1][i] < minn)
{
minn = d[S - 1][i];
x = i;
}
printf("%d\n",minn);
print(S - 1,x,n,m);
for(int i = 0;i<n;i++)
puts(map[i]);
}
return 0;
}
/*
3 5
2 0 1 2 3
3 0 3 1 2
0 2 4 1 0
8 8
1 4 1 3 4 2 4 1
4 3 1 2 0 1 2 3
3 2 1 3 0 3 1 2
2 6 5 0 2 4 1 0
5 1 2 1 3 4 2 5
5 1 3 1 5 0 1 4
5 0 6 1 4 5 3 4
0 2 2 2 3 4 1 1
6 7
3 1 2 0 1 2 3
2 1 3 0 3 1 2
6 5 0 2 4 1 0
1 2 1 3 4 2 5
1 3 1 5 0 1 4
0 6 1 4 5 3 4
4 4
0 3 1 2
2 4 1 0
3 4 2 5
5 0 1 4
*/
当然不建边,转移时直接往四个方向走也可以,代码如下:
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int INF = 0x0fffffff ;
const int MAXN = 11;
int dir_x[] = {0,0,-1,1};
int dir_y[] = {-1,1,0,0};
char map[MAXN][MAXN];
int mat[MAXN][MAXN];
int d[1<<11][MAXN][MAXN];
int val[MAXN][MAXN];
vector <int> spot;
bool inq[1<<11][MAXN][MAXN];
struct Node
{
int s,x,y;
Node(){}
Node(int a,int b,int c) : s(a),x(b),y(c) {}
};
Node path[1<<11][MAXN][MAXN];
queue <Node> q;
void init(int n,int m,int k)
{
int S = 1<<k;
for(int s = 0;s < S;s++)
for(int i = 0;i<n;i++)
for(int j = 0;j<m;j++)
d[s][i][j] = INF;
for(int i = 0;i<n;i++)
for(int j = 0;j<m;j++)
{
d[val[i][j]][i][j] = 0;
path[val[i][j]][i][j].s = 0;
}
}
void spfa(int n,int m)
{
while(!q.empty())
{
int s = q.front().s;
int x = q.front().x;
int y = q.front().y;
inq[s][x][y] = 0;
q.pop();
for(int dd = 0; dd<4;dd ++)
{
int xx = x + dir_x[dd];
int yy = y + dir_y[dd];
if(xx < 0 || xx >=n || yy < 0 || yy >=m) continue;
int to = s|val[xx][yy];
int ok = 0;
if(d[to][xx][yy] > d[s][x][y] + mat[xx][yy])
{
d[to][xx][yy] = d[s][x][y] + mat[xx][yy];
path[to][xx][yy].s = s;
path[to][xx][yy].x = x;
path[to][xx][yy].y = y;
ok = 1;
}
if(ok && !val[xx][yy] && !inq[s][xx][yy])
{
inq[s][xx][yy] = 1;
q.push(Node(s,xx,yy));
}
}
}
}
void stnt(int n,int m,int k)
{
init(n,m,k);
int S = 1<<k;
for(int s = 1;s<S;s++)
{
for(int i = 0;i<n;i++)
{
for(int j = 0;j<m;j++)
{
if(val[i][j] && !(val[i][j]&s)) continue;
for(int s1 = (s - 1)&s ; s1 ;s1 = (s1 - 1)&s)
{
int s2 = s - s1;
int tmp = d[s1|val[i][j]][i][j] + d[s2|val[i][j]][i][j] - mat[i][j] ;
if(d[s][i][j] > tmp)
{
d[s][i][j] = tmp;
path[s][i][j].s = s1|val[i][j];
path[s][i][j].x = i;
path[s][i][j].y = j;
}
}
if(d[s][i][j] < INF) q.push(Node(s,i,j)),inq[s][i][j] = 1;
}
}
spfa(n,m);
/*for(int i = 0;i<n;i++)
{
for(int j = 0;j<m;j++)
printf("s = %d,i = %d,j = %d,d = %d\n",s,i,j,d[s][i][j]);
puts("");
}*/
}
}
void print(int s,int x,int y)
{
//printf("s = %d,x = %d,y = %d,p.s = %d\n",s,x,y,path[s][x][y].s);
if(val[x][y] == 0)
{
map[x][y] = 'o';
}
if(!path[s][x][y].s) return ;
if(path[s][x][y].x == x && path[s][x][y].y == y)
{
print(path[s][x][y].s ,path[s][x][y].x,path[s][x][y].y);
print((s - path[s][x][y].s)|val[x][y],path[s][x][y].x,path[s][x][y].y);
}
else
{
print(path[s][x][y].s,path[s][x][y].x,path[s][x][y].y);
}
}
int main()
{
//freopen("D://out.txt","w",stdout);
int n,m;
while(~scanf("%d%d",&n,&m))
{
int cc = 0;
for(int i = 0;i<n;i++)
{
for(int j = 0;j<m;j++)
{
scanf("%d",&mat[i][j]);
val[i][j] = 0;
if(mat[i][j] == 0)
{
map[i][j] = 'x';
val[i][j] = 1<<cc;
cc ++;
}
else map[i][j] = '_';
}
map[i][m] = '\0';
}
stnt(n,m,cc);
int S = 1<<cc;
int x,y;
int minn = INF;
for(int i =0;i<n;i++)
for(int j = 0;j<m;j++)
if(d[S - 1][i][j] < minn)
{
minn = d[S - 1][i][j];
x = i;
y = j;
}
printf("%d\n",minn);
print(S - 1,x,y);
for(int i = 0;i<n;i++)
puts(map[i]);
}
return 0;
}
/*
4 4
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0
3 5
2 0 1 2 3
3 0 3 1 2
0 2 4 1 0
8 8
1 4 1 3 4 2 4 1
4 3 1 2 0 1 2 3
3 2 1 3 0 3 1 2
2 6 5 0 2 4 1 0
5 1 2 1 3 4 2 5
5 1 3 1 5 0 1 4
5 0 6 1 4 5 3 4
0 2 2 2 3 4 1 1
6 7
3 1 2 0 1 2 3
2 1 3 0 3 1 2
6 5 0 2 4 1 0
1 2 1 3 4 2 5
1 3 1 5 0 1 4
0 6 1 4 5 3 4
4 4
0 3 1 2
2 4 1 0
3 4 2 5
5 0 1 4
*/