算法分析与设计课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

传送门:Who's in the Middle

直接 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 最小费用最大流

传送门:"Shortest" pair of paths

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;
}
posted @ 2022-03-29 10:30  Moominn  阅读(129)  评论(0编辑  收藏  举报