算法分析与设计课POJ作业(5~10章)
第五章
POJ-1942 递推
传送门:Paths on a Grid
组合数的计算
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
#define int long long
using namespace std;
int n, m;
signed main() {
while (scanf("%lld%lld", &n, &m) != EOF) {
if (n == 0 && m == 0) break;
int sum = 1, num = n + m, cnt = 1;
n = max(n, m);
for (int i = n + 1; i <= num; i++) {
sum = sum * i / cnt;
cnt++;
}
printf("%lld\n", sum);
}
return 0;
}
POJ-2083 递归
传送门:Fractal
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
#pragma GCC potimize(2)
#pragma GCC potimize(3)
using namespace std;
int n, num;
char ch[800][800];
void work(int n, int x, int y) {
if (n == 1) {
ch[x][y] = 'X';
return;
}
int tmp = pow(3.0, n - 2);
work(n - 1, x, y);
work(n - 1, x + 2 * tmp, y);
work(n - 1, x + tmp, y + tmp);
work(n - 1, x, y + 2 * tmp);
work(n - 1, x + 2 * tmp, y + 2 * tmp);
}
int main() {
while (scanf("%d", &n) != EOF) {
if (n == -1) break;
num = pow(3.0, n - 1);
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) ch[i][j] = ' ';
ch[i][num] = '\0';
}
work(n, 0, 0);
for (int i = 0; i < num; i++) printf("%s\n", ch[i]);
printf("-\n");
}
return 0;
}
POJ-2244 约瑟夫
传送门:Eeny Meeny Moo
利用约瑟夫公式
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int x;
int main() {
while (~scanf("%d", &x) && x) {
int i;
for (i = 0; ; i++) {
int num = 0;
for (int j = 2; j < x; j++)
num = (num + i + 1) % j;
if (num == 0) break;
}
printf("%d\n", i + 1);
}
return 0;
}
POJ-1067 石子游戏
传送门:取石子游戏
威佐夫博弈问题
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int a, b;
int main() {
while(scanf("%d%d", &a, &b) != EOF) {
if (a > b) swap(a, b);
int num = b - a;
if (int((sqrt(5.0) + 1) / 2.0 * num) == a) cout << 0 << endl;
else cout << 1 << endl;
}
return 0;
}
POJ-3122 划分问题算法
传送门:Pie
二分答案,需要注意的是 π 的取值最少要到小数点后 11 位
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 1e4 + 10;
const double eps = 0.000001;
const double pi = 3.14159265359;
int t, n, f;
double sum = 0.0;
double a[maxn];
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &f);
f++;
for (int i = 1; i <= n; i++) {
scanf("%lf", &a[i]);
a[i] = a[i] * a[i] * 1.0;
sum = max(sum, a[i]);
double l = 0, r = sum, mid;
while (r - l > eps) {
mid = (l + r) / 2;
int cnt = 0;
for (int i = 1; i <= n; i++)
cnt += (int)(a[i] / mid);
if (cnt >= f) l = mid;
else r = mid;
}
printf("%.4f\n", mid * pi);
}
return 0;
}
第六章
POJ-3070 兔子序列
传送门:Fibonacci
矩阵快速幂
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int mod = 10000;
int n;
int a[2][2], res[2][2], g[2][2];
void multi(int r[][2], int g[][2]) {
memset(a, 0, sizeof(a));
for (int k = 0; k < 2; k++)
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
a[k][i] = (a[k][i] + r[k][j] * g[j][i]) % mod;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
r[i][j] = a[i][j];
}
void fastm(int n) {
while (n) {
if (n & 1) multi(res, g);
multi(g, g);
n >>= 1;
}
}
int main() {
while (cin >> n) {
if (n < 0) break;
if (n == 0) {
cout << 0 << endl;
continue;
}
n--;
res[0][0] = res[0][1] = res[1][0] = 1;
res[1][1] = 0;
g[0][0] = g[1][0] = g[0][1] = 1;
g[1][1] = 0;
fastm(n);
cout << res[1][0] << endl;
}
return 0;
}
POJ-2456 二分法
传送门:Aggressive cows
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespace std;
const int maxn = 1e5 + 10;
int n, c;
int x[maxn];
inline int search(int val) {
int l = 0, r = n + 1;
while (r - l > 1) {
int mid = l + ((r - l) >> 1);
if (x[mid] >= val) r = mid;
else l = mid;
}
return r;
}
inline bool check(int num) {
int cnt = 0, now = 1;
while (now <= n) {
cnt++;
now = search(x[now] + num);
}
return cnt >= c;
}
int main() {
scanf("%d%d", &n, &c);
for (int i = 1; i <= n; i++) scanf("%d", &x[i]);
sort(x + 1, x + 1 + n);
int l = 0, r = 1e9 + 10;
while (r - l > 1) {
int mid = l + ((r - l) >> 1);
if (check(mid)) l = mid;
else r = mid;
}
printf("%d\n", l);
return 0;
}
POJ-3737 三分法
传送门:UmBasketella
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const double pi = acos(-1.0);
const double eps = 1e-9;
double s, L, R, H, V;
inline double cal(double num) {
L = (s - pi * num * num) / pi / num;
H = sqrt(L * L - num * num);
V = pi * num * num * H / 3;
return V;
}
int main() {
while (cin >> s) {
double l = 0.0, r = sqrt(s / pi);
while (r - l > eps) {
double num1 = (l + r) / 2.0;
double num2 = (num1 + r) / 2.0;
if (cal(num1) + eps < cal(num2)) l = num1;
else r = num2;
}
R = l;
L = (s - pi * R * R) / pi / R;
H = sqrt(L * L - R * R);
V = pi * R * R * H / 3;
printf("%.2f\n%.2f\n%.2f\n", V, H, R);
}
return 0;
}
POJ-2389 大整数乘法
传送门:Bull Math
高精乘模板
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 1e4 + 10;
string s1, s2;
int a[maxn], b[maxn], c[maxn];
int main() {
cin >> s1 >> s2;
int len1 = s1.length(), len2 = s2.length();
for (int i = 0; i < len1; i++) a[len1 - i] = s1[i] - '0';
for (int i = 0; i < len2; i++) b[len2 - i] = s2[i] - '0';
for (int i = 1; i <= len1; i++)
for (int j = 1; j <= len2; j++) {
c[i + j - 1] += a[i] * b[j];
c[i + j] += c[i + j - 1] / 10;
c[i + j - 1] = c[i + j - 1] % 10;
}
int len = len1 + len2;
while (c[len] == 0 && len > 0) len--;
for (int i = len; i > 0; i--) cout << c[i];
return 0;
}
POJ-2388
直接 sort
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 1e4 + 10;
int n, a[maxn];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + 1 + n);
cout << a[n / 2 + 1];
return 0;
}
第七章
POJ-1163 数字三角形
传送门:The Triangle
从下往上 dp
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e4 + 10;
int n;
int a[maxn][maxn], dp[maxn][maxn];
int main() {
cin >> n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++) cin >> a[i][j];
for (int i = 1; i <= n; i++) dp[n][i] = a[n][i];
for (int i = n - 1; i >= 1; i--)
for (int j = 0; j <= i; j++)
dp[i][j] = a[i][j] + max(dp[i + 1][j], dp[i + 1][j + 1]);
cout << dp[1][1];
return 0;
}
POJ-3624 0/1背包
传送门:Charm Bracelet
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 10;
int n, m, ans;
int w[maxn], d[maxn], dp[maxn];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> w[i] >> d[i];
for (int i = 1; i <= n; i++)
for (int j = m; j >= w[i]; j--)
dp[j] = max(dp[j], dp[j - w[i]] + d[i]);
for (int i = 1; i <= m; i++) ans = max(ans, dp[i]);
cout << ans << endl;
return 0;
}
POJ-1384 完全背包
传送门:Piggy-Bank
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e6 + 10;
int t, e, f, n;
int p[maxn], w[maxn], dp[maxn];
int main() {
cin >> t;
while (t--) {
cin >> e >> f >> n;
memset(dp, 0x3f, sizeof(dp)); dp[0] = 0;
for (int i = 1; i <= n; i++) cin >> p[i] >> w[i];
for (int i = 1; i <= n; i++)
for (int j = w[i]; j <= f - e; j++)
dp[j] = min(dp[j], dp[j - w[i]] + p[i]);
if (dp[f - e] == INF) cout << "This is impossible." << endl;
else cout << "The minimum amount of money in the piggy-bank is " << dp[f - e] << "." << endl;
}
return 0;
}
POJ-2139 负权最短路
传送门:Six Degrees of Cowvin Bacon
跑一个 floyd
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e4 + 10;
const int maxm = 505;
int n, m, num, ans = INF;
int x[maxn], g[maxm][maxm];
int main() {
cin >> n >> m;
memset(g, 0x3f, sizeof(g));
for (int i = 1; i <= n; i++) g[i][i] = 0;
for (int i = 1; i <= m; i++) {
cin >> num;
for (int j = 1; j <= num; j++) cin >> x[j];
for (int j = 1; j <= num; j++)
for (int k = j + 1; k <= num; k++)
g[x[j]][x[k]] = g[x[k]][x[j]] = 1;
}
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
for (int i = 1; i <= n; i++) {
int sum = 0;
for (int j = 1; j <= n; j++) sum += g[i][j];
ans = min(ans, sum);
}
cout << (ans * 100) / (n - 1) << endl;
return 0;
}
第八章
POJ-1321 回溯算法
传送门:棋盘问题
挑了个最简单的,没什么恶心人的细节,直接 dfs 就完事了
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
int n, k, ans;
char vis[10], ch[10][10];
void dfs(int x, int num) {
if (num == k) {
ans++;
return;
}
if (x == n + 1) return;
for (int i = 1; i <= n; i++) {
if (ch[x][i] == '#' && !vis[i]) {
vis[i] = 1;
dfs(x + 1, num + 1);
vis[i] = 0;
}
}
dfs(x + 1, num);
}
int main() {
while (cin >> n >> k) {
if (n == -1 && k == -1) break;
memset(vis, 0, sizeof(vis)); ans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) cin >> ch[i][j];
dfs(1, 0);
cout << ans << endl;
}
return 0;
}
第九章
POJ-3278 分支界限
传送门:Catch That Cow
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 1e5 + 10;
int n, k;
int step[maxn];
bool vis[maxn];
inline int bfs(int n, int k) {
queue<int> q;
q.push(n);
step[n] = 0; vis[n] = 1;
while (!q.empty()) {
int now = q.front(); q.pop();
for (int i = 1; i <= 3; i++) {
int nxt;
if (i == 1) nxt = now - 1;
else if (i == 2) nxt = now + 1;
else nxt = now * 2;
if (nxt < 0 || nxt >= maxn) continue;
if (vis[nxt] == 0) {
q.push(nxt);
step[nxt] = step[now] + 1;
vis[nxt] = 1;
}
if (nxt == k) return step[k];
}
}
}
int main() {
cin >> n >> k;
if (n >= k) cout << n - k << endl;
else cout << bfs(n, k) << endl;
return 0;
}
第十章
POJ-1273 最大流
传送门:Drainage Ditches
模板题,用的 ISAP
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 10010;
int n, m, s, t, cnt = 1;
int head[maxn], vis[maxn];
int dep[maxn], num[maxn], cur[maxn], p[maxn];
struct node{
int u, v, nxt, cap, flow;
}e[maxn * 10];
inline void add(int u, int v, int w) {
e[++cnt].u = u; e[cnt].v = v;
e[cnt].cap = w; e[cnt].flow = 0;
e[cnt].nxt = head[u]; head[u] = cnt;
}
inline void bfs() {
memset(vis, 0, sizeof(vis));
queue<int> q;
vis[t] = 1; dep[t] = 0;
q.push(t);
while (!q.empty()) {
int now = q.front(); q.pop();
for (int i = head[now]; i; i = e[i].nxt)
if (vis[e[i].v] == 0 && e[i].cap == 0) {
vis[e[i].v] = 1;
dep[e[i].v] = dep[now] + 1;
q.push(e[i].v);
}
}
}
inline int agument() {
int x = t, ans = INF;
while (x != s) {
ans = min(ans, e[p[x]].cap - e[p[x]].flow);
x = e[p[x]].u;
}
x = t;
while (x != s) {
e[p[x]].flow += ans;
e[p[x] ^ 1].flow -= ans;
x = e[p[x]].u;
}
return ans;
}
int ISAP() {
int flow = 0;
int x = s;
memset(num, 0, sizeof(num));
for (int i = 1; i <= n; i++) num[dep[i]]++;
for (int i = 1; i <= cnt; i++) cur[i] = head[i];
while (dep[s] < n) {
if (x == t) {
flow += agument();
x = s;
}
int flag = 0;
for (int i = cur[x]; i; i = e[i].nxt)
if (e[i].cap > e[i].flow && dep[x] == dep[e[i].v] + 1) {
flag = 1;
p[e[i].v] = i;
cur[x] = i;
x = e[i].v;
break;
}
if (flag == 0) {
if (--num[dep[x]] == 0) break;
int mn = n - 1;
for (int i = head[x]; i; i = e[i].nxt)
if (e[i].cap > e[i].flow) mn = min(mn, dep[e[i].v]);
dep[x] = mn + 1;
num[dep[x]]++;
cur[x] = head[x];
if (x != s) x = e[p[x]].u;
}
}
return flow;
}
inline void init() {
memset(head, 0, sizeof(head));
cnt = 1;
}
signed main() {
while (cin >> m >> n) {
init();
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
add(u, v, w); add(v, u, 0);
}
s = 1; t = n;
bfs();
int ans = ISAP();
cout << ans << endl;
}
return 0;
}
POJ-3068 最小费用最大流
dfs 会超时,使用一个 pre 数组记录
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 110;
int n, m, s, t, cnt = -1, ret, sum;
int head[maxn], vis[maxn], dis[maxn], pre[maxn], flow[maxn];
struct node{
int u, v, nxt, cap, flow;
}e[20010];
inline void add(int u, int v, int w, int c) {
e[++cnt].v = v; e[cnt].u = u;
e[cnt].flow = w; e[cnt].cap = c;
e[cnt].nxt = head[u]; head[u] = cnt;
}
inline bool spfa(int s, int t) {
queue<int> q;
memset(vis, 0, sizeof(vis));
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0; vis[s] = 1; flow[s] = INF;
q.push(s);
while (!q.empty()) {
int now = q.front(); q.pop();
vis[now] = 0;
for (int i = head[now]; i != -1; i = e[i].nxt) {
int to = e[i].v;
if (e[i].flow && dis[to] > dis[now] + e[i].cap) {
dis[to] = dis[now] + e[i].cap;
pre[to] = i;
flow[to] = min(flow[now], e[i].flow);
if (vis[to]) continue;
vis[to] = 1;
q.push(to);
}
}
}
return dis[t] != INF;
}
int mcmf(int s, int t) {
int ans = 0;
while (spfa(s, t)) {
int x = t;
while (x != s) {
int i = pre[x];
e[i].flow -= flow[t];
e[i ^ 1].flow += flow[t];
x = e[i].u;
}
ans += flow[t]; ret += dis[t] * flow[t];
}
return ans;
}
inline void init() {
memset(head, -1, sizeof(head));
cnt = -1; ret = 0;
}
int main() {
while (scanf("%d%d", &n, &m)) {
init(); sum++;
if (n == 0 && m == 0) break;
s = 0; t = n + 1;
add(s, 1, 2, 0); add(1, s, 0, 0);
add(n, t, 2, 0); add(t, n, 0, 0);
for (int i = 1; i <= m; i++) {
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
add(u + 1, v + 1, 1, c); add(v + 1, u + 1, 0, -c);
}
int ans = mcmf(s, t);
printf("Instance #%d: ", sum);
if (ans < 2) printf("Not possible\n");
else printf("%d\n", ret);
}
return 0;
}