Uva11624 - Fire!
迷宫问题。有多个起火点,每一时刻所有起火点向上下左右四个蔓延。
必须在某处起火之前才能通过该处。问人逃出迷宫的最短时间。
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int,int> pii;
#define x first
#define y second
const int maxn = 1005, inf = 1e9;
char mat[maxn][maxn];
int t[maxn][maxn];
int dx[4] = {-1,1,0,0};
int dy[4] = {0,0,-1,1};
void bfs(int r, int c){
memset(t, -1, sizeof(t));
queue<pii > que;
for(int i = 0; i < r; i++)
for(int j = 0; j < c; j++)
if(mat[i][j] == 'F'){
que.push(pii(i,j));
t[i][j] = 0;
}
while(!que.empty()){
pii cur = que.front(); que.pop();
int nt = t[cur.x][cur.y] + 1;
for(int i = 0,x,y; i < 4; i++){
x = cur.x + dx[i];
y = cur.y + dy[i];
if(x >= 0 && x < r && y >= 0 && y < c && mat[x][y] != '#' && t[x][y] == -1){
t[x][y] = nt;
que.push(pii(x,y));
}
}
}
}
int t2[maxn][maxn];
int bfs2(int r, int c){
int ans = inf;
memset(t2, -1, sizeof(t2));
queue<pii > que;
for(int i = 0; i < r; i++)
for(int j = 0; j < c; j++)
if(mat[i][j] == 'J'){
que.push(pii(i,j));
t2[i][j] = 0;
goto quitt;
}
quitt:
while(!que.empty()){
pii cur = que.front(); que.pop();
int nt = t2[cur.x][cur.y] + 1;
if(nt >= ans) continue;
for(int i = 0,x,y; i < 4; i++){
x = cur.x + dx[i];
y = cur.y + dy[i];
if(x >= 0 && x < r && y >= 0 && y < c){
if( mat[x][y] != '#' && t2[x][y] == -1 && (t[x][y] == -1 || nt < t[x][y]) ){//一开始没有t[x][y]==-1的判断,结果wa了,果然还是姿势不够优美
t2[x][y] = nt;
que.push(pii(x,y));
}
}else{
if(nt < ans) ans = nt;
}
}
}
if(ans == inf) ans = -1;
return ans;
}
void solve(){
int r, c;
scanf("%d%d", &r, &c);
for(int i = 0; i < r; i++) scanf("%s", mat[i]);
bfs(r,c);
int ans = bfs2(r, c);
if(~ans) printf("%d\n", ans);
else puts("IMPOSSIBLE");
}
int main(){
// freopen("in", "r", stdin);
// freopen("out", "w", stdout);
int t;
scanf("%d", &t);
while(t--) solve();
return 0;
}
Uva10054 The Necklace
多状态迷宫问题。在每个位置除了方向,还有车轮的着地面是哪一面(共5面)。
多设几个状态就可以了。
代码写的太挫,一堆bug,样例调了好久才过...以后还是用怎么清晰怎么来的风格写。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
typedef pair<int,int> pii;
const int maxn = 27;
char mat[maxn][maxn];
bool vis[maxn][maxn][5][6];
int m, n;
struct status{
int x, y, dir, seg, t;
status(){}
status(int x, int y, int dir, int seg, int t):
x(x), y(y), dir(dir), seg(seg), t(t){}
};
queue<status > que;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
int bfs(int x, int y){
while(!que.empty()) que.pop();
que.push(status(x,y,0,0,0));
memset(vis, 0, sizeof(vis));
vis[x][y][0][0] = 1;
int dir, seg, nx, ny;
while(!que.empty()){
status cur = que.front(); que.pop();
cur.t++;
x = cur.x, y = cur.y;
dir = cur.dir, seg = cur.seg;
nx = x + dx[dir], ny = y + dy[dir];
seg++, seg %= 5;
if(nx >= 0 && nx < m && ny >= 0 && ny < n && mat[nx][ny] != '#' && !vis[nx][ny][dir][seg]){
if(mat[nx][ny] == 'T' && !seg) return cur.t;
vis[nx][ny][dir][seg] = 1;
que.push( status(nx,ny,dir,seg, cur.t) );
}
dir++; dir %= 4;
if(!vis[x][y][dir][cur.seg]){
vis[x][y][dir][cur.seg] = 1;
cur.dir = dir;
que.push(cur);
}
dir -= 2, dir += 4, dir %= 4;
if(!vis[x][y][dir][cur.seg]){
vis[x][y][dir][cur.seg] = 1;
cur.dir = dir;
que.push(cur);
}
}
return -1;
}
void solve(){
for(int i = 0; i < m; i++) scanf("%s", mat[i]);
int ans;
for(int i = 0, f = 0; i < m && !f; i++)
for(int j = 0; j < n && !f; j++)
if(mat[i][j] == 'S'){
ans = bfs(i, j);
f = 1;
}
if(~ans)
printf("minimum time = %d sec\n", ans);
else
puts("destination not reachable");
}
int main(){
// freopen("in", "r", stdin);
// freopen("out", "w", stdout);
int cas = 1;
while(~scanf("%d%d", &m, &n) && n && m){
if(cas > 1) puts("");
printf("Case #%d\n", cas++);
solve();
}
return 0;
}
Uva10054 The Necklace
偶拉回路。先判断图是否连通,以及每个点度数都为偶数。
那么只剩下打印路径。注意递归时打印路径的语句应该在递归调用的后面。
而且打印的路径是反向的,所以应该将u,v逆序输出,或者压到栈里,最后再输出。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <stack>
using namespace std;
const int maxn = 55, maxm = 1001<<1;
int head[maxn], ec, d[maxn], vis[maxm];
struct Edge{
int v, nx;
Edge(){}
Edge(int v, int nx): v(v), nx(nx){}
}e[maxm];
inline void init(){
memset(head, -1, sizeof(head)); ec = 0;
memset(d, 0, sizeof(d));
memset(vis, 0, sizeof(vis));
}
inline void add(int u, int v){
e[ec] = Edge(v, head[u]); head[u] = ec++;
}
inline void addEdge(int u, int v){
add(u, v); add(v, u);
}
int n, m;
typedef pair<int,int> pii;
stack<pii > sta;
void dfs(int u){
for(int i = head[u]; ~i; i = e[i].nx)if(!vis[i]){
vis[i] = vis[i^1] = 1;
int v = e[i].v;
dfs(v);
printf("%d %d\n", v, u);
// sta.push(pii(u,v));
}
}
bool vis0[maxn];
void dfs0(int u){
vis0[u] = 1;
for(int i = head[u]; ~i; i = e[i].nx){
int v = e[i].v;
if(vis0[v]) continue;
dfs0(v);
}
}
bool check(){
memset(vis0, 0, sizeof(vis0));
for(int i = 1; i <= n; i++)
if(d[i]){
dfs0(i);
break;
}
for(int i = 1; i <= n; i++)
if(d[i] && !vis0[i])
return false;
return true;
}
void solve(){
init();
n = 50;
scanf("%d", &m);
for(int i = 0, u, v; i < m; i++){
scanf("%d%d", &u, &v);
addEdge(u, v);
d[u]++, d[v]++;
}
if(!check()){
puts("some beads may be lost");
return;
}
for(int i = 1; i <= n; i++)
if(d[i]&1){
puts("some beads may be lost");
return;
}
while(!sta.empty()) sta.pop();
for(int i = 1; i <= n; i++)
if(d[i]){
dfs(i);
break;
}
// pii cur;
// while(!sta.empty()){
// cur = sta.top(); sta.pop();
// printf("%d %d\n", cur.first, cur.second);
// }
}
int main(){
freopen("in", "r", stdin);
freopen("out2", "w", stdout);
int t, cas = 1;
scanf("%d", &t);
while(t--){
if(cas > 1) puts("");
printf("Case #%d\n", cas++);
solve();
}
return 0;
}
Uva1423 - Guess
对于n个数a[i],给出s(i,j)=a[i]+a[i+1]+...+a[j]与0的大小关系。(1<=i<=n,i<=j<=n)
求任意满足以上关系的n个数来,而且ABS(a[i]) <= 10.
首先利用前缀和来表示区间和,将以上关系转换成前缀和的大小关系,利用拓扑排序,可找到一个满足的解。
然后由前缀和推出n个数的一个解。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <iomanip>
using namespace std;
const int maxn = 12, inf = 1e8;
char buf[maxn*maxn];
int mat[maxn][maxn];
void addEdge(int u, int v, int w){
mat[u][v] = w, mat[v][u] = -w;;
}
int ans[maxn], in[maxn];
int topo(int n){
for(int i = 0; i < n; i++) ans[i] = inf;
memset(in, 0, sizeof(in));
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
if(mat[i][j] == 1) in[j]++;
// printf(" inD ");
// for(int i = 0; i < n; i++)
// printf("%d ", in[i]); puts("");
for(int t = 0; t < n; t++){
int u = 0;
for(;u<=n;u++)if(!in[u])break;
if(u>n)return 0;
if(!t)ans[u] = 0;
in[u]--;
for(int v = 0; v <= n; v++)
if(mat[u][v]==1)ans[v] = min(ans[v], ans[u]-1),in[v]--;
else if(mat[u][v] == -1) ans[v] = max(ans[v], ans[u]+1);
else if(mat[u][v]==0)ans[v] = ans[u];
}
return 1;
}
void solve(){
int n;
scanf("%d%s", &n, buf);
for(int i = 0; i <= n+1; i++)
for(int j = 0; j <= n+1; j++)
mat[i][j] = -2;
for(int i = n, s = 0; i >= 1; i--){
int beg = n - i + 1;
for(int j = 1; j <= i; j++, s++){
if(buf[s] == '+')addEdge(beg+j-1, beg-1, 1);
else if(buf[s] == '-')addEdge(beg-1, beg+j-1, 1);
else addEdge(beg+j-1, beg-1, 0);
}
}
// for(int i = 0; i <= n; i++){
// for(int j = 0; j <= n; j++)
// cout << setw(3) << mat[i][j] << " " ;
// cout << endl;
// }
// puts("");
topo(n+1);
for(int i = 0; i < n; i++)
printf(i==n-1?"%d\n":"%d ", ans[i+1] - ans[i]);
// puts("\n");
}
int main(){
// freopen("in", "r", stdin);
// freopen("out", "w", stdout);
int t;
scanf("%d", &t);
while(t--){
solve();
}
return 0;
}