23-25 October in 614

Practice

sort

给定一系列形如 \(A<B\) 的不等关系,判断前 \(k\) 个不等关系是否即可确定 \(n\) 个元素之间的大小顺序;如果不可确定,判断前 \(k\) 个不等关系是否即存在矛盾。

例如:

[input 1]
4 6
A<B
A<C
B<C
C<D
B<D
A<B

[output 1]
Sorted sequence determined after 4 relations: ABCD.

[input 2]
3 2
A<B
B<A

[output 2]
Inconsistency found after 2 relations.

[input 3]
26 1
A<Z

[output 3]
Sorted sequence cannot be determined.

利用拓扑序判断:

当没有点入度为 0,或当最终入队的点的个数 \(< n\) 时,不等关系存在矛盾。

当有不止一个点入度为 0,或当取同一个队首 \(u\) 时有不止一个 \(v\) 的入度变为 0 时,不等关系不足以推定所有元素顺序。

否则,拓扑序即为元素顺序。

总的来说,思路须要理清才能完整无误地写出程序。

/* P1347 排序
 * Au: GG
 */
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;

int n, m, ans, t;
char buf[6], lst[30];
int head[30], nex[900], to[900], d[30], du[30];

inline void add(int x, int y) {
    nex[++head[0]]=head[x], head[x]=head[0], to[head[0]]=y;
    ++du[y];
}

inline int toposort() {
    memcpy(d, du, sizeof du);
    memset(lst, 0, sizeof lst);
    queue<int> q;
    int p=0, pp=0, cnt=0, res=0;
    for (int i=1; i<=n; i++) if (!d[i]) q.push(i), ++p;
    if (p>1) res=2;
    while (!q.empty()) {
        int now=q.front(); q.pop(); pp=0, ++cnt, lst[++lst[0]]='A'+now-1;
        for (int k=head[now]; k; k=nex[k]) {
            if (--d[to[k]]==0) {
                q.push(to[k]);
                if (pp++) res=2;
            }
        }
    }
    if (cnt<n) return 1;
    return res;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i=1; i<=m; i++) {
        scanf("%s", buf), add(buf[0]-'A'+1, buf[2]-'A'+1);
        ans=toposort();
        if (ans<2) {t=i; break; }
    }
    if (!ans) printf("Sorted sequence determined after %d relations: %s.\n", t, lst+1);
    else if (ans<2) printf("Inconsistency found after %d relations.\n", t);
    else printf("Sorted sequence cannot be determined.\n");
    return 0;
}

[POI2012] HUR-Warehouse Store

\(n\) 天。第 \(i\) 天上午会进货 \(A_i\) 件商品,中午的时候会有顾客需要购买 \(B_i\) 件商品,可以选择满足顾客的要求,或是无视掉他。如果要满足顾客的需求,就必须要有足够的库存。问最多能够满足多少个顾客的需求。

贪心。思路不难。

注意 priority_queue 默认为大根堆,所以实现大根要定义小于关系,实现小根要定义大于关系。(被坑了)

/* [POI2012]HUR-Warehouse Store
 * Au: GG
 */
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long

int n, a[250003], b[250003], ans, cnt;
ll tot;

struct node {
    int id, val;
    bool operator < (const node& A) const {return val<A.val; }
};

priority_queue<node> q;

int main() {
    scanf("%d", &n);
    for (int i=1; i<=n; i++) scanf("%d", &a[i]);
    for (int i=1; i<=n; i++) scanf("%d", &b[i]);
    for (int i=1; i<=n; i++) {
        tot+=a[i];
        if (tot>=b[i]) tot-=b[i], ++ans, q.push((node) {i, b[i]});
        else if (!q.empty() && q.top().val>b[i]) tot+=q.top().val-b[i], q.pop(), q.push((node) {i, b[i]});
    }
    printf("%d\n", ans);
    while (!q.empty()) a[++cnt]=q.top().id, q.pop();
    sort(a+1, a+cnt+1);
    for (int i=1; i<=cnt; i++) printf("%d ", a[i]);
    return 0;
}

password

给定三个数 \(n\)\(a\)\(b\)\(x\)\(y\) 满足下面的一些条件:

  1. $x \operatorname{and} y=y $;
  2. \((ax+by) \operatorname{xor} (ay+bx)\) 最大;
  3. \(1\le x,y\le n\)

\(x\)\(y\)。其中:and 表示按位与,xor 表示按位异或。

显然,二进制下 \(y\subseteq x\)。所以只需要枚举 \(x\)\(y\) 用生成子集的方法(如下)。

for (int x=1; x<=n; x++) 
    for (int y=x; y; y=(y-1)&x) { // 生成子集(不包括空集)
        calc=(a*y+b*x)^(a*x+b*y);
        if (calc>ans) ans=calc, ax=x, ay=y;
    }

最大边权最小的最短路

\(G=(V,E)\) 是无向图,每条边 \(E_i\) 有一个边权 \(W_i\)。 要求以起点为 \(s\),终点为 \(t\),寻找一条路径,使路径上最大的边权 \(W_\max\) 最小。

Floyd 算法,状态转移方程改为:

\[g(i,j)=\min\Big(g(i,j), \max\big(g(i,k), g(k,j)\big)\Big),i,j,k\in V \]

posted @ 2018-10-23 21:35  greyqz  阅读(139)  评论(0编辑  收藏  举报