HDU 4848 Wow! Such Conquering!
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4848
题意及思路:有n个星球,现在你从1开始需要访问其他所有的星球。给你Txy表示从x到y的时间,再给n-1个Deadline表示第一次到星球2~n的最迟时间不能超过所给的Deadline。现在问你是否能在要求内访问所有的星球,如果可以输出最小的时间,否则输出-1。
主体思路是dfs,不过必须要进行剪枝,通过时间是否超过Deadline可以剪去一部分,如果当前应该选取的路径耗时Tij加上之前所用的时间已经大于结果ans,便可枚举下个状态了
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <climits>
#include <utility>
using namespace std;
const int inf = INT_MAX;
int n, ans;
int t[31][31];
int dead[31], vis[31];
void floyd()
{
for(int k = 0; k < n; k++)
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
if(t[i][j] > t[i][k] + t[k][j])
t[i][j] = t[i][k] + t[k][j];
}
}
void dfs(int s, int cnt, int ti, int sum)
{
if(cnt == 0)
{
if(ans > sum)
ans = sum;
return ;
}
for(int i = 0; i < n; i++)
{
if(!vis[i] && ti + t[s][i] > dead[i])
return ;
}
for(int i = 0; i < n; i++)
{
if(vis[i] || sum + t[s][i] >= ans)
continue;
vis[i] = 1;
dfs(i, cnt - 1, ti + t[s][i], sum + cnt * t[s][i]);
vis[i] = 0;
}
}
int main()
{
int i, j;
while(~scanf("%d", &n))
{
ans = inf;
memset(vis, 0, sizeof(vis));
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
scanf("%d", &t[i][j]);
for(i = 1; i < n; i++)
scanf("%d", &dead[i]);
floyd();
vis[0] = 1;
dfs(0, n - 1, 0, 0);
if(ans == inf)
cout << -1 << endl;
else
cout << ans << endl;
}
return 0;
}
HDU 4849 Wow! Such City!
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4849
题意及思路:告诉你两点间的距离公式,然后再用Dijkstra求出0到 其他点的最短路即可
#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxd = 1005;
const int maxn = maxd * maxd;
const long long inf = 1e18;
int n, m;
ll x[maxn], y[maxn], z[maxn];
ll c[maxd][maxd], d[maxd];
int vis[maxd];
ll dijstra ()
{
for (int i = 0; i < n; i++)
d[i] = inf;
d[0] = 0;
vis[0] = 1;
ll ans = inf;
for (int i = 0; i < n; i++)
{
int p = 0;
ll tmp = inf;
for (int j = 0; j < n; j++)
{
if (d[j] < tmp && vis[j] == 0)
{
p = j;
tmp = d[j];
}
}
vis[p] = 1;
if (p != 0 && d[p] % m < ans)
ans = d[p] % m;
for (int j = 0; j < n; j++)
{
if (d[p] + c[p][j] < d[j])
d[j] = d[p] + c[p][j];
}
}
return ans;
}
int main ()
{
while (scanf("%d%d%I64d%I64d%I64d%I64d", &n, &m, &x[0], &x[1], &y[0], &y[1]) == 6)
{
memset(vis, 0, sizeof(vis));
for (int i = 2; i < n * n; i++)
{
x[i] = (12345 + x[i - 1] * 23456 + x[i - 2] * 34567 + (x[i - 1] * x[i - 2] % 5837501) * 45678) % 5837501;
y[i] = (56789 + y[i - 1] * 67890 + y[i - 2] * 78901 + (y[i - 1] * y[i - 2] % 9860381) * 89012) % 9860381;
}
for(int i = 1; i < n * n; i++)
z[i] = (x[i] * 90123 + y[i]) % 8475871 + 1;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (i == j)
c[i][j] = 0;
else
c[i][j] = z[i * n + j];
}
}
printf("%I64d\n", dijstra());
}
return 0;
}
HDU 4850 Wow! Such String!
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4850
题意及思路:构造一个长度为N(1 ≤ N ≤ 500000)的小写字母字符串,要求所有长度大于等于4的子串只能出现一次。不能构造输出“Impossible”。
长度大于等于4的子串统一可以转化为长度为4的子串,所能构造出的最大长度为26^4+3,末尾的3个字符共有26^3种组合,每种抽象成一个节点。每个节点添加新字符有26种情况,抽象成26条有向边,指向转化后的节点。每经过一条图中的边,就是构造一个长度为4的子串的过程。由于子串不能重复,那么每条边就至多只能走一次,每个节点的入度和出度均为26,故而存在欧拉回路满足题目要求。
直接构造:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <utility>
using namespace std;
const int maxn = 26 * 26 * 26 * 30;
bool vis[26][26][26][26];
int s[maxn], l;
void tc()
{
int i;
memset(vis, 0, sizeof(vis));
for(i = 0; i < 26; i++)
{
s[l] = s[l + 1] = s[l + 2] = s[l + 3] = i;
l += 4;
}
for(i = 3; i < l; i++)
vis[s[i]][s[i - 1]][s[i - 2]][s[i - 3]] = 1;
while(1)
{
int flag = 0;
for(i = 0; i < 26; i++)
{
if(!vis[i][s[l - 1]][s[l - 2]][s[l - 3]])
{
flag = 1;
s[l] = i;
vis[s[l]][s[l - 1]][s[l - 2]][s[l - 3]] = 1;
l++;
}
}
if(!flag)
break;
}
}
int main()
{
int n;
tc();
while(~scanf("%d", &n))
{
if(l < n)
puts("Impossible");
else
{
for(int i = 0; i < n; i++)
printf("%c", s[i] + 'a');
printf("\n");
}
}
return 0;
}
HDU 4856 Tunnels
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4856
题意及思路:给你N*N的网格,‘.’表示可以走,‘#’表示不能走,m条管道,每条管道有起点和终点坐标,Bob每次可以走到相邻的网格花费1s,问走完m条管道要花多少时间,在管道内不计算时间,起点随意
利用BFS和旅行商问题模板解决,不会状态压缩,思路是队友给的=、=
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <utility>
using namespace std;
const int inf = 1e9;
char s[30][30];
int vis[30][30];
int x1[30], x2[30], y1[30], y2[30];
int n, m;
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
int d[30][30];
int dp[1 << 15][15];
typedef pair<int, int> p;
void bfs(int x, int y)
{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
vis[i][j] = inf;
vis[x][y] = 0;
queue <p> que;
que.push(p(x, y));
while(!que.empty())
{
p tq = que.front();
que.pop();
for(int i = 0; i < 4; i++)
{
int nx = tq.first + dx[i], ny = tq.second + dy[i];
if(nx > 0 && nx <= n && ny > 0 && ny <= n && vis[nx][ny] == inf && s[nx][ny] != '#')
{
que.push(p(nx, ny));
vis[nx][ny] = vis[tq.first][tq.second] + 1;
}
}
}
}
void solve()
{
for(int s = 0; s < 1 << m; s++)
{
fill(dp[s], dp[s] + m, inf);
}
for(int i = 0; i < m; i++)
dp[(1 << m) - 1][i] = 0;
for(int s = (1 << m) - 2; s >= 0; s--)
{
for(int v = 0; v < m; v++)
{
for(int u = 0; u < m; u++)
{
if(!(s >> u & 1))
{
dp[s][v] = min(dp[s][v], dp[s | 1 << u][u] + d[v][u]);
}
}
}
}
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
int i, j, ans = inf;
for(i = 1; i <= m; i++)
for(j = 1; j <= m; j++)
{
if(i == j)
d[i][j] = 0;
else
d[i][j] = inf;
}
for(i = 1; i <= n; i++)
scanf(" %s", s[i] + 1);
for(i = 1; i <= m; i++)
scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
for(i = 1; i <= m; i++)
{
bfs(x2[i], y2[i]);
for(j = 1; j <= m; j++)
{
if(i == j)
continue;
d[i - 1][j - 1] = vis[x1[j]][y1[j]];
}
}
solve();
for(i = 0; i < m; i++)
{
ans = min(ans, dp[0][i]);
}
if(ans == inf)
cout << -1 << endl;
else
cout << ans << endl;
}
return 0;
}