Kuangbin专题三Dancing Links

没写完所有的,因为要去上课了赶紧先预习一下,这就先发出来吧。

跳舞链这东西以前在hihocoder上翻到过,当时看的模模糊糊的,现在好好学一学。
暂时写到了精确覆盖和重复覆盖两种,板子稍微有点区别。

2018.8.5开始继续更新:从北大回来了,继续刷广斌!先把剩下的四道题刷了。

A - Exact cover HUST - 1017

板子题,和hihocoder上那道题差不多,多了个答案栈。hust没法交,也不知道写的对不对。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
using namespace std;
typedef pair<int, int> P;
#define N 1010
#define M 100010
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int h[M], s[M], row[M], col[M], u[M], d[M], l[M], r[M];
int ans[N], cnt;

void init(int n, int m)
{
    rep(i, 0, m){
        s[i] = 0;
        l[i] = i - 1;
        r[i] = i + 1;
        u[i] = d[i] = i;
    }
    l[0] = m;
    r[m] = 0;
    rep(i, 0, n) h[i] = -1;
}

void link(int x, int y, int id)
{
    row[id] = x; col[id] = y;
    u[id] = u[y]; d[id] = y;
    d[u[y]] = id;
    u[y] = id;
    s[y]++;
    if(h[x] == -1) h[x] = l[id] = r[id] = id;
    else{
        l[id] = l[h[x]];
        r[id] = h[x];
        r[l[h[x]]] = id;
        l[h[x]] = id;
    }
}

void remove(int y)
{
    l[r[y]] = l[y];
    r[l[y]] = r[y];

    for(int i = d[y]; i != y; i = d[i]){
        for(int j = r[i]; j != i; j = r[j]){
            u[d[j]] = u[j];
            d[u[j]] = d[j];
            --s[col[j]];
        }
    }
}

void resume(int y)
{
    for(int i = u[y]; i != y; i = u[i]){
        for(int j = l[i]; i != j; j = l[j]){
            d[u[j]] = u[d[j]] = j;
            ++s[col[j]];
        }
    }
    l[r[y]] = r[l[y]] = y;
}

bool dance(int deep)
{//cout << deep << endl;
    if(r[0] == 0) {
        cnt = deep;
        return true;
    }
    int id = r[0];
    for(int i = r[0]; i != 0; i = r[i])
        if(s[i] < s[id]) id = i;
    remove(id);
    for(int i = d[id]; i != id; i = d[i]){
        ans[deep] = row[i];
    //cout << i << endl;
        for(int j = l[i]; j != i; j = l[j])
            remove(col[j]);
        if(dance(deep + 1)) return true;
        for(int j = r[i]; j != i; j = r[j])
            resume(col[j]);
    }
    resume(id);
    return false;
}

int main()
{
    freopen("data.txt", "r", stdin);
    int n, m, t, y, id;
    while(~scanf("%d%d", &n, &m)){
        id = m;
        init(n, m);
        rep(x, 1, n) {
            scanf("%d", &t);
            while(t--){
                scanf("%d", &y);
                link(x, y, ++id);
            }
        }
        if(!dance(0)) puts("NO");
        else{
           // sort(ans, ans + cnt);
            printf("%d", cnt);
            rep(i, 0, cnt - 1) printf(" %d", ans[i]);
        }
    }
    return 0;
}

B - Treasure Map ZOJ - 3209

这一题主要难在建模上。思想是把二维的n*m图以及那些小长方形拉成一维的,也就变成了板子题。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
using namespace std;
typedef pair<int, int> P;
#define N 1000
#define M 500010
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int s[M], col[M], row[M], l[M], r[M], u[M], d[M];
int h[N], ans;

void init(int n, int m)
{
    rep(i, 0, m) {
        s[i] = 0;
        l[i] = i - 1;
        r[i] = i + 1;
        u[i] = d[i] = i;
    }
    l[0] = m;
    r[m] = 0;
    rep(i, 0, n) h[i] = -1;
    ans = INF;
}

void link(int x, int y, int id)
{
    col[id] = y; row[id] = x;
    s[y]++;
    u[id] = u[y];
    d[id] = y;
    d[u[y]] = id;
    u[y] = id;
    if(h[x] == -1) h[x] = l[id] = r[id] = id;
    else{
        l[id] = l[h[x]];
        r[id] = h[x];
        r[l[h[x]]] = id;
        l[h[x]] = id;
    }
}

void remove(int id)
{
    l[r[id]] = l[id]; r[l[id]] = r[id];
    for(int i = d[id]; i != id; i = d[i]){
        for(int j = r[i]; j != i; j = r[j]){
            u[d[j]] = u[j];
            d[u[j]] = d[j];
            --s[col[j]];
        }
    }
}

void resume(int id)
{
    for(int i = u[id]; i != id; i = u[i]){
        for(int j = l[i]; j != i; j = l[j]){
            u[d[j]] = d[u[j]] = j;
            ++s[col[j]];
        }
    }
    l[r[id]] = r[l[id]] = id;
}

void dance(int deep)
{
    if(ans < deep) return;
    if(r[0] == 0){
        ans = min(ans, deep);
        return;
    }
    int id = r[0];
    remove(id);
    for(int i = d[id]; i != id; i = d[i]){
        for(int j = l[i]; j != i; j = l[j])
            remove(col[j]);
        dance(deep + 1);
        for(int j = r[i]; j != i; j = r[j])
            resume(col[j]);
    }
    resume(id);
}

int main()
{
    //freopen("data.txt", "r", stdin);
    int t, n, m, p, x1, y1, x2, y2, id;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d%d", &n, &m, &p);
        init(p, n * m);
        id = n * m;
        rep(i, 1, p) {
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            rep(j, x1 + 1, x2) rep(k, y1 + 1, y2)
                link(i, (j - 1) * m + k, ++id);
        }
        dance(0);
        if(ans == INF) puts("-1");
        else printf("%d\n", ans);
    }
    return 0;
}

C - Radar HDU - 2295

重复覆盖的DIX+二分+A*。
woc太难了woc,Orz。
首先看了波重复覆盖的DIX,比起精确覆盖少删了行。但是删的操作变化有点大。精确覆盖的代码:

void remove(int id)
{
    l[r[id]] = l[id]; r[l[id]] = r[id];
    for(int i = d[id]; i != id; i = d[i]){
        for(int j = r[i]; j != i; j = r[j]){
            u[d[j]] = u[j];
            d[u[j]] = d[j];
            --s[col[j]];
        }
    }
}

void resume(int id)
{
    for(int i = u[id]; i != id; i = u[i]){
        for(int j = l[i]; j != i; j = l[j]){
            u[d[j]] = d[u[j]] = j;
            ++s[col[j]];
        }
    }
    l[r[id]] = r[l[id]] = id;
}
void dance()
    int id = r[0];
    remove(id);
    for(int i = d[id]; i != id; i = d[i]){
        for(int j = l[i]; j != i; j = l[j])
            remove(col[j]);
        dance(deep + 1);
        for(int j = r[i]; j != i; j = r[j])
            resume(col[j]);
    }
    resume(id);

重复覆盖的代码:

 void remove(int id){
        for(int i = d[id]; i != id; i = d[i]){
            l[r[i]] = l[i]; r[l[i]] = r[i];
        }
    }
    void resume(int id){
        for(int i = u[id]; i != id; i = u[i]){
            l[r[i]] = r[l[i]] = i;
        }
    }

 void dance(int deep){

        if(deep + f() >= cnt) return;
        if(r[0] == 0){
            cnt = min(cnt, deep); return;
        }
        int id = r[0];
        for(int i = r[0]; i != 0; i = r[i])
            if(s[i] < s[id]) id = i;

        for(int i = d[id]; i != id; i = d[i]){
            remove(i);
            for(int j = r[i]; j != i; j = r[j]) remove(j);
            dance(deep + 1);
            for(int j = l[i]; j != i; j = l[j]) resume(j);
            resume(i);
        }
    }

注意到精确覆盖的删除函数收到的参数都是第几列,是把一整列和那一列1元素所在行删除,那一列一个remove就干净了,s数组为0,r[0]那一行再也看不见这一列。而重复覆盖会温柔许多,remove接受的参数是节点id,仅仅把id节点其他行在那一列的元素删除,意味着这一列不用操心了,以后选其他行不用考虑会不会覆盖到这一列。我觉得操作一下两种覆盖不一定要写的这么不一样, 但是网上都是这么写的那就这样吧。
第二个点是A*思想,用精确覆盖求出当前的底线来剪枝。
第三个点是二分答案,我二分的题还真做的不多,这么有二分味道的题就是没想法 ,还是太菜了。
精度也要卡eps。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
using namespace std;
typedef pair<int, int> P;
#define N 510
#define M 1000010
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

struct DLX{
    int col[M], row[M], u[M], l[M], r[M], d[M];
    int n, m, sz, cnt;
    int h[N], s[N];
    void init(int nn, int mm){
        n = nn; m = mm;
        rep(i, 0, m) {
            u[i] = d[i] = i;
            l[i] = i - 1; r[i] = i + 1;
            s[i] = 0;
        }
        l[0] = m; r[m] = 0;
        sz = m;
        rep(i, 0, n) h[i] = -1;
        cnt = INF;
    }
    void link(int x, int y){
        ++sz;
        s[y]++;
        col[sz] = y; row[sz] = x;
        u[sz] = u[y];
        d[sz] = y;
        d[u[y]] = sz;
        u[y] = sz;
        if(h[x] == -1) h[x] = l[sz] = r[sz] = sz;
        else{
            l[sz] = l[h[x]];
            r[sz] = h[x];
            r[l[h[x]]] = sz;
            l[h[x]] = sz;
        }
    }
    void remove(int id){
        for(int i = d[id]; i != id; i = d[i]){
            l[r[i]] = l[i]; r[l[i]] = r[i];
        }
    }
    void resume(int id){
        for(int i = u[id]; i != id; i = u[i]){
            l[r[i]] = r[l[i]] = i;
        }
    }

    bool v[N];
    int f(){
        int ret = 0;
        for(int i = r[0]; i != 0; i = r[i]) v[i] = true;
        for(int i = r[0]; i != 0; i = r[i]){
            if(v[i]){
                v[i] = false;
                ret++;
                for(int j = d[i]; j != i; j = d[j]){
                    for(int k = r[j]; k != j; k = r[k]){
                        v[col[k]] = false;
                    }
                }
            }
        }
        return ret;
    }
    void dance(int deep){

        if(deep + f() >= cnt) return;
        if(r[0] == 0){
            cnt = min(cnt, deep); return;
        }
        int id = r[0];
        for(int i = r[0]; i != 0; i = r[i])
            if(s[i] < s[id]) id = i;

        for(int i = d[id]; i != id; i = d[i]){
            remove(i);
            for(int j = r[i]; j != i; j = r[j]) remove(j);
            dance(deep + 1);
            for(int j = l[i]; j != i; j = l[j]) resume(j);
            resume(i);
        }
    }
}g;

int main()
{
    //freopen("data.txt", "r", stdin);

    bool vis[N];
    double x1[55], y1[55], x2[55], y2[55];
    int n, m, t, k;
    scanf("%d", &t);
    while(t--){
        scanf("%d%d%d", &n, &m, &k);
        rep(i, 1, n) scanf("%lf%lf", &x1[i], &y1[i]);
        rep(i, 1, m) scanf("%lf%lf", &x2[i], &y2[i]);

        double l = 0, r = 2000, mid;

        int num;
        while(l + eps < r){
            mid = (l + r) / 2;
            num = 0;
            g.init(m, n);
            memset(vis, false, sizeof vis);

            rep(i, 1, m) rep(j, 1, n) {
                double dis1 = (x2[i] - x1[j]) * (x2[i] - x1[j]);
                double dis2 = (y2[i] - y1[j]) * (y2[i] - y1[j]);
                if(dis1 + dis2 <= mid * mid){
                    if(!vis[j]) num++;
                    g.link(i, j);
               //     cout << "i j " <<i <<' ' << j << endl;
                    vis[j] = true;
                }
            }

            if(num < n) l = mid;
            else{
                g.dance(0);
             //   cout << g.cnt << endl;
                if(g.cnt <= k) r = mid;
                else l = mid;
            }
        }
        printf("%.6lf\n", l);
    }

    return 0;
}

D - 神龙的难题 FZU - 1686

又是一道重复覆盖的题,还是那个板子,因为一个小错误T了好久。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
using namespace std;
typedef pair<int, int> P;
#define N 300
#define M 90010
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int n, m, n1, m1, maze[17][17];
struct DLX{
int u[M], d[M], l[M], r[M], row[M], col[M], h[M], s[N];
int n, m, cnt, sz;

void init(int nn, int mm)
{
    n = nn; m = mm;
    rep(i, 0, m){
        u[i] = d[i] = i;
        l[i] = i - 1; r[i] = i + 1;
        s[i] = 0;
    }
    l[0] = m; r[m] = 0;
    rep(i, 0, n) h[i] = -1;
    cnt = INF;
    sz = m;
}

void link(int x, int y)
{
    ++sz;
    row[sz] = x; col[sz] = y;
    u[sz] = u[y];
    d[sz] = y;
    d[u[y]] = sz;
    u[y] = sz;
    if(h[x] == -1) h[x] = l[sz] = r[sz] = sz;
    else{
        l[sz] = l[h[x]];
        r[sz] = h[x];
        r[l[h[x]]] = sz;
        l[h[x]] = sz;
    }
    s[y]++;
}


void remove(int id)
{
    for(int i = d[id]; i != id; i = d[i])
        l[r[i]] = l[i], r[l[i]] = r[i];
}

void resume(int id)
{
    for(int i = u[id]; i != id; i = u[i])
        l[r[i]] = r[l[i]] = i;
}

bool v[M];
int f()
{
    int ret = 0;
    for(int i = r[0]; i != 0; i = r[i]) v[i] = true;
    for(int i = r[0]; i != 0; i = r[i]) if(v[i]){
        v[i] = false; ret++;
        for(int j = d[i]; j != i; j = d[j]){
            for(int k = r[j]; k != j; k = r[k])
                v[col[k]] = false;
        }
    }
    return ret;
}
void dance(int deep)
{
    if(deep + f() >= cnt) return;
    if(r[0] == 0){
        cnt = min(cnt, deep); return;
    }
    int id = r[0];//cout << id << ' ' << d[id] << ' ' << d[9] << endl;
    for(int i= r[0]; i != 0; i = r[i])
        if(s[i] < s[id]) id = i;
    for(int i = d[id]; i != id; i = d[i]){
        remove(i);//cout << deep << endl;
        for(int j = r[i]; j != i; j = r[j]) remove(j);
        dance(deep + 1);
        for(int j = l[i]; j != i; j = l[j]) resume(j);
        resume(i);
    }
}
}g;

int main()
{
   // freopen("data.txt", "r", stdin);

    int a, b, id;
    while(~scanf("%d%d", &a, &b)){
        id = 0;
        rep(i, 1, a) rep(j, 1, b) {
            scanf("%d", &maze[i][j]);
            if(maze[i][j]) maze[i][j] = ++id;
        }
        scanf("%d%d", &n1, &m1);
        g.init(a * b, id);
        rep(i, 1, a) rep(j, 1, b) {
            rep(k, i, i + n1 - 1) rep(l, j, j + m1 - 1) if(k <= a && l <= b){
                if(maze[k][l]){
                    g.link((i - 1) * b + j, maze[k][l]);
                   // cout << (i - 1) * a + j << ' ' << g[k][l] << endl;
                }
            }
        }
///cout << n << ' ' << m << endl;
        g.dance(0);
        printf("%d\n", g.cnt);
    }

    return 0;
}

E - Square Destroyer POJ - 1084

这题也是难在建模上,看到网上的大佬博客用位运算存储状态,Orz。刚了很久才写出来,虽然我本来就有正确的思路,但是实现起来真不会。
大佬博客

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 61
#define M 4000
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

struct DLX{
    int u[M], d[M], l[M], r[M], row[M], col[M];
    int h[M], s[N];
    int cnt, sz, n, m;

    void init(int nn, int mm){
        n = nn; m = mm;
        rep(i, 0, m){
            u[i] = d[i] = i;
            l[i] = i - 1; r[i] = i + 1;
            s[i] = 0;
        }
        l[0] = m; r[m] = 0;
        rep(i, 0, n) h[i] = -1;
        cnt = INF; sz = m;
    }

    void link(int x, int y){
    //cout << x << ' ' << y << endl;
        ++sz;
        row[sz] = x; col[sz] = y;
        u[sz] = u[y]; d[sz] = y;
        d[u[y]] = sz; u[y] = sz;
        s[y]++;
        if(h[x] == -1) h[x] = l[sz] = r[sz] = sz;
        else {
            l[sz] = l[h[x]];
            r[sz] = h[x];
            r[l[h[x]]] = sz;
            l[h[x]] = sz;
        }
    }

    void remove(int id){
        for(int i = d[id]; i != id; i = d[i])
            l[r[i]] = l[i], r[l[i]] = r[i];
    }

    void resume(int id){
        for(int i = u[id]; i != id; i = u[i])
            l[r[i]] = r[l[i]] = i;
    }

    bool v[N];
    int f(){
        int ret = 0;
        for(int i = r[0]; i != 0; i = r[i]) v[i] = true;
        for(int i = r[0]; i != 0; i = r[i]) if(v[i]) {
            ret++; v[i] = false;
            for(int j = d[i]; j != i; j = d[j])
                for(int k = r[j]; k != j; k = r[k])
                    v[col[k]] = false;
        }
    }

    void dance(int deep) {
        if(deep + f() >= cnt) return;
        if(r[0] == 0){
            cnt = min(cnt, deep); return;
        }
        int id = r[0];
        for(int i = r[0]; i != 0; i = r[i])
            if(s[i] < s[id]) id = i;
        for(int i = d[id]; i != id; i = d[i]){
            remove(i);
            for(int j = r[i]; j != i; j = r[j]) remove(j);
            dance(deep + 1);
            for(int j = l[i]; j != i; j = l[j]) resume(j);
            resume(i);
        }
    }
}g;


vector<ll> v[6];
int rowid[N][N], colid[N][N], valid[N];
ll st;
int t, n, m, k, tmp, tot, nn, mm;
bool vis[N];

void init_sq(int n)
{
    v[n].clear();
    int cnt = 0;
    rep(i, 0, n - 1) {
        rep(j, 0, n - 1) rowid[i][j] = cnt++;
        rep(j, 0, n) colid[i][j] = cnt++;
    }
    rep(j, 0, n) rowid[n][j] = cnt++;

    rep(i, 0, n - 1) rep(j, 0, n - 1) rep(k, 1, n) {
        if(i + k > n || j + k > n) break;
        ll val = 0;
        rep(l, 0, k - 1) val |= (1ll << rowid[i][j + l]);
        rep(l, 0, k - 1) val |= (1ll << colid[i + l][j]);
        rep(l, 0, k - 1) val |= (1ll << rowid[i + k][j + l]);
        rep(l, 0, k - 1) val |= (1ll << colid[i + l][j + k]);
        v[n].push_back(val);
    }
}
void solve(){
    int sz = v[n].size();

    mm = 0;

    rep(i, 0, sz - 1) if((st & v[n][i]) == v[n][i]){
        valid[mm++] = i;
        //cout << "valid " << i + 1 << endl;
    }

    if(mm == 0) {
        puts("0"); return;
    }
    g.init(tot, mm);
//cout << "mm " << mm << endl;

    rep(i, 0, tot - 1) {
        if (vis[i]) {
            rep(j, 0, mm - 1) {
                if (v[n][valid[j]] & (1LL << i))
                    g.link(i + 1, j + 1);
                    //cout << "i, j " << i + 1 << ' ' << j + 1 << endl;
            }
        }
    }
//    int x = 1;
//    rep(i, 0, sz - 1) if((st & v[n][i]) == v[n][i]) {
//        rep(j, 0, tot - 1) if(vis[j] && (v[n][i] & (1ll << j))) {
//
//            cout << "i, j " << i + 1 << ' ' << j + 1 << endl;
//        }
//        x++;
//    }

    g.dance(0);
    printf("%d\n", g.cnt);
}

int main()
{
    freopen("data.txt", "r", stdin);

    rep(i, 1, 5) init_sq(i);
//    int size = v[2].size();
//    rep(i, 0, size - 1) {printf("x %d\n", i + 1);rep(j, 0, 24) {
//       if(v[2][i] & (1ll << j)) printf("%d ", j + 1);
//       if(j == 24) putchar('\n');
//    }}
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &k);
        memset(vis, true, sizeof vis);
        tot = n * (n + 1) * 2;
        st = (1ll << tot) - 1;

        rep(i, 1, k) {
            scanf("%d", &tmp); vis[--tmp] = false;
            st ^= (1ll << tmp);
        }
//cout << "st " << st << endl;
//ll tmp = st;
//    while(tmp){
//        cout << (tmp & 1) ;
//        tmp >>= 1;
//    }cout << endl;
        solve();
    }

    return 0;
}

F - Sudoku POJ - 3074

数独问题,也是难在建模上,建模不仅想法难,实现起来也难,我调试了好久的bug,板子敲都敲错了一个地方。这种把限制条件转换成列的思想初步形成。
学习的这里的

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 800
#define M 3645
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

struct DLX{
    int u[M], d[M], l[M], r[M], col[M], row[M];
    int h[M], s[M];
    int cnt, sz, n, m, ans[N];

    void init(int nn, int mm){
        n = nn; m = mm;
        rep(i, 0, m) {
            u[i] = d[i] = i;
            l[i] = i - 1; r[i] = i + 1;
            s[i] = 0;
        }
        rep(i, 0, n) h[i] = -1;
        l[0] = m; r[m] = 0;
        cnt = INF;
        sz = mm;
    }
    void link(int x, int y){
        ++sz;
        if(h[x] == -1) h[x] = l[sz] = r[sz] = sz;
        else{
            l[sz] = l[h[x]];
            r[sz] = h[x];
            r[l[h[x]]] = sz;
            l[h[x]] = sz;
        }

        row[sz] = x;//cout << sz << endl;
        col[sz] = y;
        u[sz] = u[y];
        d[sz] = y;
        d[u[y]] = sz;
        u[y] = sz;
        s[y]++;
        //if(r[0] != 1)cout <<"link " << r[0] << ' ' << x << ' ' << y << ' '<< sz <<endl;
    }
    void remove(int id){
        l[r[id]] = l[id]; r[l[id]] = r[id];
        for(int i = d[id]; i != id; i = d[i]){
            for(int j = r[i]; j != i; j = r[j]){
                d[u[j]] = d[j]; u[d[j]] = u[j];
                s[col[j]]--;
            }
        }
    }
    void resume(int id){
        for(int i = u[id]; i != id; i = u[i]){
            for(int j = l[i]; j != i; j = l[j]){
                d[u[j]] = u[d[j]] = j;
                s[col[j]]++;
            }
        }
        l[r[id]] = r[l[id]] = id;
    }
    bool dance(int deep){//cout << deep << ' ' << r[0] << endl;
        if(r[0] == 0) {
            cnt = deep;
            return true;
        }
        int id = r[0];//cout <<"dance " << sz << endl;
        for(int i = r[0]; i != 0; i = r[i]){
            if(s[i] < s[id]) id = i;//cout << "i " << i << endl;
        }
//cout << id << endl;
        remove(id);//cout << d[id] << endl;
        for(int i = d[id]; i != id; i = d[i]){//cout << "r[0] " << r[0] << endl;
            ans[deep] = row[i];//cout << row[i] << endl;
            for(int j = l[i]; j != i; j = l[j]) remove(col[j]);
            if(dance(deep + 1)) return true;
            for(int j = r[i]; j != i; j = r[j]) resume(col[j]);
        }
        resume(id);
        return false;
    }
}g;

char s[90];
struct node{
   int x, y, v;
}st[N];
int main()
{
    freopen("data.txt", "r", stdin);

    while(~scanf("%s", s) && s[0] != 'e'){
        g.init(800, 324);
        int x = 1;
        rep(i, 0, 8) rep(j, 0, 8) if(s[i * 9 + j] == '.'){
            rep(v, 1, 9) {
                g.link(x, i * 9 + j + 1);//cout << x << ' ' << i*9+j+1 << endl;
                g.link(x, 81 + i * 9 + v);//cout<<x <<' ' << 81+i*9+v<<endl;
                g.link(x, 162 + j * 9 + v);//cout<<x<<' ' << 162+j*9+v<< endl;
                g.link(x, 243 + (3 * (i / 3) + (j + 3) / 3 - 1) * 9 + v);
              //  cout<<x<<' '<<243+(3*(i/3)+(j+3)/3-1)*9+v<< ' ' <<i<<' ' <<j<<endl;
                st[x].x = i; st[x].y = j; st[x].v = v;
                x++;
                //cout << g.sz << ' ' << x << endl;if(g.sz == 323) cout << endl;
                //cout << i <<' ' << j <<' '<< v << endl;
            }
        }
        else{
            int v = s[i * 9 + j] - '0';
            g.link(x, i * 9 + j + 1);//cout << x << ' ' << i*9+j+1 << endl;
            g.link(x, 81 + i * 9 + v);//cout<<x <<' ' << 81+i*9+v<<endl;
            g.link(x, 162 + j * 9 + v);//cout<<x<<' ' << 162+j*9+v<< endl;
            g.link(x, 243 + (3 * (i / 3) + (j + 3) / 3 - 1) * 9 + v);
            //cout<<x<<' '<<243+(3*(i/3)+(j+1)/3-1)*9+v<<' ' <<243+(((i)/3)*3+(j+1)/3-1)*9+v<<endl;
            st[x].x = i; st[x].y = j; st[x].v = v;
            x++;
            //cout << g.sz << ' ' << x << endl;
            //if(g.sz == 323) cout << "i, j" <<  i << ' ' << j << endl;
            //cout << i <<' ' << j <<' '<< v << endl;
        }
//    for(int i = g.d[0]; i != 0; i = g.d[i]){
//        cout << i << endl;
//    }
//cout << g.sz << ' ' << x << endl;
        g.dance(0);
//cout << g.cnt << endl;
        rep(i, 0, g.cnt - 1){
            s[st[g.ans[i]].x * 9 + st[g.ans[i]].y] = '0' + st[g.ans[i]].v;
        }
        s[g.cnt] = '\0';
        printf("%s\n", s);
    }

    return 0;
}

G - Sudoku ZOJ - 3122

和上一题差不多,试了试前插法的板子。这种题目错误太容易犯,还是尽量靠近板子。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define M 16
#define MN 5000
#define MM 1034
#define MNN 20000
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

struct DLX{
    int u[MNN], d[MNN], l[MNN], r[MNN], col[MNN], row[MNN];
    int h[MN], s[MM];
    int cnt, sz, n, m, ans[MN];

    void init(int nn, int mm){
        n = nn; m = mm;
        rep(i, 0, m) {
            u[i] = d[i] = i;
            l[i] = i - 1; r[i] = i + 1;
            s[i] = 0;
        }
        rep(i, 0, n) h[i] = -1;
        l[0] = m; r[m] = 0;
        cnt = INF;
        sz = mm;
    }
    void link(int x, int y){
        ++sz;
        if(h[x] == -1) h[x] = l[sz] = r[sz] = sz;
        else{
            r[sz] = r[h[x]];
            l[sz] = h[x];
            l[r[h[x]]] = sz;
            r[h[x]] = sz;
        }

        row[sz] = x;
        col[sz] = y;
        d[sz] = d[y];
        u[sz] = y;
        u[d[y]] = sz;
        d[y] = sz;
        s[y]++;
    }
    void remove(int id){
        l[r[id]] = l[id]; r[l[id]] = r[id];
        for(int i = d[id]; i != id; i = d[i]){
            for(int j = r[i]; j != i; j = r[j]){
                d[u[j]] = d[j]; u[d[j]] = u[j];
                s[col[j]]--;
            }
        }
    }
    void resume(int id){
        for(int i = u[id]; i != id; i = u[i]){
            for(int j = l[i]; j != i; j = l[j]){
                d[u[j]] = u[d[j]] = j;
                s[col[j]]++;
            }
        }
        l[r[id]] = r[l[id]] = id;
    }
    bool dance(int deep){
        if(r[0] == 0) {
            cnt = deep;
            return true;
        }
        int id = r[0];
        for(int i = r[0]; i != 0; i = r[i]){
            if(s[i] < s[id]) id = i;
        }

        remove(id);
        for(int i = d[id]; i != id; i = d[i]){
            ans[deep] = row[i];
            for(int j = l[i]; j != i; j = l[j]) remove(col[j]);
            if(dance(deep + 1)) return true;
            for(int j = r[i]; j != i; j = r[j]) resume(col[j]);
        }
        resume(id);
        return false;
    }
    void place(int &r, int &c1, int &c2, int &c3, int &c4, int i, int j, int k){
        r = (i * 16 + j) * 16 + k;
        c1 = i * 16 + j + 1;
        c2 = 256 + i * 16 + k;
        c3 = 256 * 2 + j * 16 + k;
        c4 = 256 * 3 + ((i / 4) * 4 + (j / 4)) * 16 + k;
    }
}g;

char s[20][20];

int main()
{
    //freopen("data.txt", "r", stdin);

    int t = 0;
    while(~scanf("%s", s[0])){
        rep(i, 1, 15) scanf("%s", s[i]);
        g.init(16*16*16, 16*16*4);

        int r, c1, c2, c3, c4;
        rep(i, 0, 15) rep(j, 0, 15) rep(k, 1, 16) if(s[i][j] == '-' || s[i][j] == k - 1 + 'A'){
            g.place(r, c1, c2, c3, c4, i, j, k);
            g.link(r, c1); g.link(r, c2); g.link(r, c3); g.link(r, c4);
        }

        g.dance(0);
        int v,x,y;
        for(int i=0;i<g.cnt;i++){
            v=(g.ans[i]-1)%M;
            x=(g.ans[i]-1)/M/M;
            y=(g.ans[i]-1)/M%M;
            s[x][y]=v+'A';
        }
        if(t++) puts("");
        rep(i, 0, 15) printf("%s\n", s[i]);
    }

    return 0;
}

Squiggly Sudoku HDU - 4069

Today we play a squiggly sudoku, The objective is to fill a 9*9 grid with digits so that each column, each row, and each of the nine Connecting-sub-grids that compose the grid contains all of the digits from 1 to 9.
Left figure is the puzzle and right figure is one solution.

Now, give you the information of the puzzle, please tell me is there no solution or multiple solution or one solution.
Input
The first line is a number T(1<=T<=2500), represents the number of case. The next T blocks follow each indicates a case.
Each case contains nine lines, Each line contains nine integers.
Each module number tells the information of the gird and is the sum of up to five integers:
0~9: ‘0’ means this gird is empty, ‘1’ - ‘9’ means the gird is already filled in.
16: wall to the up
32: wall to the right
64: wall to the down
128: wall to the left
I promise there must be nine Connecting-sub-grids, and each contains nine girds.
Output
For each case, if there are Multiple Solutions or no solution just output “Multiple Solutions” or “No solution”. Else output the exclusive solution.(as shown in the sample output)
Sample Input
3
144 18 112 208 80 25 54 144 48
135 38 147 80 121 128 97 130 32
137 32 160 144 114 167 208 0 32
192 100 160 160 208 96 183 192 101
209 80 39 192 86 48 136 80 114
152 48 226 144 112 160 160 149 48
128 0 112 166 215 96 160 128 41
128 39 153 32 209 80 101 136 35
192 96 200 67 80 112 208 68 96

144 48 144 81 81 16 53 144 48
128 96 224 144 48 128 103 128 38
163 208 80 0 37 224 209 0 32
135 48 176 192 64 112 176 192 104
192 101 128 89 80 82 32 150 48
149 48 224 208 16 48 224 192 33
128 0 114 176 135 0 80 112 169
137 32 148 32 192 96 176 144 32
192 96 193 64 80 80 96 192 96

144 88 48 217 16 16 80 112 176
224 176 129 48 128 40 208 16 37
145 32 128 96 196 96 176 136 32
192 32 227 176 144 80 96 192 32
176 192 80 98 160 145 80 48 224
128 48 144 80 96 224 183 128 48
128 36 224 144 51 144 32 128 105
131 64 112 136 32 192 36 224 176
224 208 80 64 64 116 192 83 96
Sample Output
Case 1:
521439678
763895124
984527361
346182795
157964832
812743956
235678419
479216583
698351247
Case 2:
No solution
Case 3:
Multiple Solutions

先染色再建图再跑一遍跳舞链。坑点是要搜到一次就记录答案,否则继续搜会破坏答案栈里的内容。
因为这WA了一晚上Orz。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define M 16
#define MN 5000
#define MM 1034
#define MNN 20000
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

struct path {
  int x, y, v;
}pre[9 * 9 * 9 + 1];
int out[9][9];

struct DLX{
    int u[MNN], d[MNN], l[MNN], r[MNN], col[MNN], row[MNN];
    int h[MN], s[MM];
    int cnt, sz, n, m, ans[MN], flag;

    void init(int nn, int mm){
        n = nn; m = mm;
        rep(i, 0, m) {
            u[i] = d[i] = i;
            l[i] = i - 1; r[i] = i + 1;
            s[i] = 0;
        }
        rep(i, 0, n) h[i] = -1;
        l[0] = m; r[m] = 0;
        cnt = INF;
        sz = mm;
        flag = 0;
    }
    void link(int x, int y){
        ++sz;
        if(h[x] == -1) h[x] = l[sz] = r[sz] = sz;
        else{
            r[sz] = r[h[x]];
            l[sz] = h[x];
            l[r[h[x]]] = sz;
            r[h[x]] = sz;
        }

        row[sz] = x;
        col[sz] = y;
        d[sz] = d[y];
        u[sz] = y;
        u[d[y]] = sz;
        d[y] = sz;
        s[y]++;
    }
    void remove(int id){
        l[r[id]] = l[id]; r[l[id]] = r[id];
        for(int i = d[id]; i != id; i = d[i]){
            for(int j = r[i]; j != i; j = r[j]){
                d[u[j]] = d[j]; u[d[j]] = u[j];
                s[col[j]]--;
            }
        }
    }
    void resume(int id){
        for(int i = u[id]; i != id; i = u[i]){
            for(int j = l[i]; j != i; j = l[j]){
                d[u[j]] = u[d[j]] = j;
                s[col[j]]++;
            }
        }
        l[r[id]] = r[l[id]] = id;
    }
    void dance(int deep){
        if(flag >= 2) return;
        if(r[0] == 0) {
            cnt = deep;
            flag++;
            rep(i, 0, cnt - 1) {
                int x = pre[ans[i]].x, y = pre[ans[i]].y, v = pre[ans[i]].v;
                out[x][y] = v;
            }
            return ;
        }
        int id = r[0];
        for(int i = r[0]; i != 0; i = r[i]){
            if(s[i] < s[id]) id = i;
        }

        remove(id);
        for(int i = d[id]; i != id; i = d[i]){
            ans[deep] = row[i];
            for(int j = l[i]; j != i; j = l[j]) remove(col[j]);
            dance(deep + 1);
            if(flag >= 2) return;
            for(int j = r[i]; j != i; j = r[j]) resume(col[j]);
        }
        resume(id);
    }
}g;

int data[9][9];
int wall[9][9];
int grids[9][9];
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};

int getwall(int num){
    return num >> 4;
}

void bfs(int sx, int sy, int color)
{
    queue<P> que;
    P h;
    int x, y;
    que.push(P(sx, sy));
    grids[sx][sy] = color;

    while(!que.empty()) {
        h = que.front(); que.pop();
        rep(i, 0, 3) {
            if(wall[h.fi][h.se] & (1 << i)) continue;
            x = h.fi + dx[i], y = h.se + dy[i];
            if(grids[x][y] >= 0) continue;
            grids[x][y] = color;
            que.push(P(x, y));
        }
    }
}

int main()
{
   // freopen("data.txt", "r", stdin);

    int t;
    scanf("%d", &t);
    rep(Case, 1, t) {
        g.init(9 * 9 * 9, 9 * 9 * 4);
        rep(i, 0, 8) rep(j, 0, 8) scanf("%d", &data[i][j]);
        memset(grids, -1, sizeof grids);

        rep(i, 0, 8) rep(j, 0, 8)
            wall[i][j] = getwall(data[i][j]);
//        rep(i, 0, 8) rep(j, 0, 8) {
//            printf("%2d ", wall[i][j]);
//            if(j == 8) putchar('\n');
//        }

        int ret = 0;
        rep(i, 0, 8) rep(j, 0, 8)
            if(grids[i][j] < 0) bfs(i, j, ret++);
//        rep(i, 0, 8) rep(j, 0, 8) {
//            cout << grids[i][j];
//            if(j == 8) putchar('\n');
//        }

        int row = 1;
        rep(i, 0, 8) rep(j, 0, 8) rep(k, 1, 9){
            if((data[i][j] ^ (wall[i][j] << 4)) == k || !(data[i][j] ^ (wall[i][j] << 4))) {
               // cout << i << ' ' << j << ' ' << k <<endl;
                g.link(row, 9 * 9 * 0 + i * 9 + j + 1);
                g.link(row, 9 * 9 * 1 + i * 9 + k);
                g.link(row, 9 * 9 * 2 + j * 9 + k);
                g.link(row, 9 * 9 * 3 + grids[i][j] * 9 + k);
                pre[row].x = i;
                pre[row].y = j;
                pre[row].v = k;
                row++;
            }
        }
        printf("Case %d:\n", Case);
        g.dance(0);
        if(g.flag == 0) puts("No solution");
        else if(g.flag >= 2) puts("Multiple Solutions");
        else {
            rep(i, 0, 8) rep(j, 0, 8) {
                printf("%d", out[i][j]);
                if(j == 8) putchar('\n');
            }
        }
    }

    return 0;
}

Divisibility HDU - 3335

As we know,the fzu AekdyCoin is famous of math,especially in the field of number theory.So,many people call him “the descendant of Chen Jingrun”,which brings him a good reputation.
AekdyCoin also plays an important role in the ACM_DIY group,many people always ask him questions about number theory.One day,all members urged him to conduct a lesson in the group.The rookie daizhenyang is extremely weak at math,so he is delighted.
However,when AekdyCoin tells us “As we know, some numbers have interesting property. For example, any even number has the property that could be divided by 2.”,daizhenyang got confused,for he don’t have the concept of divisibility.He asks other people for help,first,he randomizely writes some positive integer numbers,then you have to pick some numbers from the group,the only constraint is that if you choose number a,you can’t choose a number divides a or a number divided by a.(to illustrate the concept of divisibility),and you have to choose as many numbers as you can.
Poor daizhenyang does well in neither math nor programming.The responsibility comes to you!
Input
An integer t,indicating the number of testcases,
For every case, first a number n indicating daizhenyang has writen n numbers(n<=1000),then n numbers,all in the range of (1…2^63-1).
Output
The most number you can choose.
Sample Input
1
3
1 2 3
Sample Output
2

Hint:
If we choose 2 and 3,one is not divisible by the other,which is the most number you can choose.

我是猪油蒙了心竟然写精确覆盖!!!换成重复覆盖就过了。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 10000
#define M 200000
#define MN 5000
#define MM 1034
#define MNN 20000
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

struct DLX{
    int col[M], row[M], u[M], l[M], r[M], d[M];
    int n, m, sz, cnt;
    int h[N], s[N];
    void init(int nn, int mm){
        n = nn; m = mm;
        rep(i, 0, m) {
            u[i] = d[i] = i;
            l[i] = i - 1; r[i] = i + 1;
            s[i] = 0;
        }
        l[0] = m; r[m] = 0;
        sz = m;
        rep(i, 0, n) h[i] = -1;
        cnt = 0;
    }
    void link(int x, int y){
        ++sz;
        s[y]++;
        col[sz] = y; row[sz] = x;
        u[sz] = u[y];
        d[sz] = y;
        d[u[y]] = sz;
        u[y] = sz;
        if(h[x] == -1) h[x] = l[sz] = r[sz] = sz;
        else{
            l[sz] = l[h[x]];
            r[sz] = h[x];
            r[l[h[x]]] = sz;
            l[h[x]] = sz;
        }
    }
    void remove(int id){
        for(int i = d[id]; i != id; i = d[i]){
            l[r[i]] = l[i]; r[l[i]] = r[i];
        }
    }
    void resume(int id){
        for(int i = u[id]; i != id; i = u[i]){
            l[r[i]] = r[l[i]] = i;
        }
    }

    bool v[N];
    int f(){
        int ret = 0;
        for(int i = r[0]; i != 0; i = r[i]) v[i] = true;
        for(int i = r[0]; i != 0; i = r[i]){
            if(v[i]){
                v[i] = false;
                ret++;
                for(int j = d[i]; j != i; j = d[j]){
                    for(int k = r[j]; k != j; k = r[k]){
                        v[col[k]] = false;
                    }
                }
            }
        }
        return ret;
    }
    void dance(int deep){

        if(deep + f() <= cnt) return;
        if(r[0] == 0){
            cnt = max(cnt, deep); return;
        }
        int id = r[0];
        for(int i = r[0]; i != 0; i = r[i])
            if(s[i] < s[id]) id = i;

        for(int i = d[id]; i != id; i = d[i]){
            remove(i);
            for(int j = r[i]; j != i; j = r[j]) remove(j);
            dance(deep + 1);
            for(int j = l[i]; j != i; j = l[j]) resume(j);
            resume(i);
        }
    }
}g;
//  1 2 3 4 5
//1 1 1 1 1 1
//2 1 1 0 1 0
//3 1 0 1 0 0
//4 1 1 0 1 0
//5 1 0 0 0 1
ll num[1001];

int main()
{
   // freopen("data.txt", "r", stdin);

    int t, n;
    scanf("%d", &t);
    while(t--) {
        scanf("%d", &n);
        rep(i, 0, n - 1) scanf("%lld", &num[i]);
        sort(num, num + n);
        g.init(n, n);
        rep(i, 0, n - 1) rep(j, 0, n - 1)
            if(num[j] % num[i] == 0 || num[i] % num[j] == 0)
                g.link(i + 1, j + 1);

        g.dance(0);
        printf("%d\n", g.cnt);
    }

    return 0;
}

A simple math problem. HDU - 4979

Dragon loves lottery, he will try his luck every week. One day, the lottery company brings out a new form of lottery called accumulated lottery. In a normal lottery, you pick 7 numbers from N numbers. You will get reward according to how many numbers you match. If you match all 7 numbers, you will get the top prize for 1 billion dollars!!! Unlike normal lottery, an M-accumulated lottery allows you to pick M numbers from N numbers. If M is big enough, this may significantly increase your possibility to win. (Of course it cost more…)

Some people buy multiple accumulated lotteries to guarantee a higher possibility to get the top prize. Despite of this, it’s still not worthy to guarantee a top prize.Knowing this, Dragon changes his target to second tier prize. To get a second tier prize, you need to contain all of the R numbers with M numbers picked.Given N, M and R, Dragon wants to know how many M-accumulated lotteries he needs to buy, so that he can guarantee that he can get at least the second tier prize.
Input
The first line of input contains only one integer T, the number of test cases.

For each case, there’s a single line contains N, M and R(1<=R<=M<=N<=8).
Output
Each output should occupy one line. Each line should start with “Case #i: “, with i implying the case number. For each case, just output the result with no other leading or tailing spaces.
Sample Input
3
2 1 1
2 2 1
2 2 2
Sample Output
Case #1: 2
Case #2: 1
Case #3: 1

这题真好玩,百度下来是个打表题。。这个矩阵的建立有点东西的,这个把所有组合的状态列举出来有点难,Orz。大神是枚举出每种状态,对每种状态分类,对号入座。另外位运算我再不加括号我是狗。。。。。。。。

//#include <queue>
//#include <cstdio>
//#include <cstring>
//#include <utility>
//#include <iostream>
//#include <map>
//#include <algorithm>
//#include <cmath>
//#include <string>
//#include <vector>
//using namespace std;
//typedef pair<int, int> P;
//typedef long long ll;
//#define N 10000
//#define M 200000
//#define MN 5000
//#define MM 1034
//#define MNN 20000
//const int INF = 0x3f3f3f3f;
//const double eps = 1e-8;
//#define fi first
//#define se second
//#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)
//
//struct DLX{
//    int col[M], row[M], u[M], l[M], r[M], d[M];
//    int n, m, sz, cnt;
//    int h[N], s[N];
//    void init(int nn, int mm){
//        n = nn; m = mm;
//        rep(i, 0, m) {
//            u[i] = d[i] = i;
//            l[i] = i - 1; r[i] = i + 1;
//            s[i] = 0;
//        }
//        l[0] = m; r[m] = 0;
//        sz = m;
//        rep(i, 0, n) h[i] = -1;
//        cnt = INF;
//    }
//    void link(int x, int y){
//        ++sz;
//        s[y]++;
//        col[sz] = y; row[sz] = x;
//        u[sz] = u[y];
//        d[sz] = y;
//        d[u[y]] = sz;
//        u[y] = sz;
//        if(h[x] == -1) h[x] = l[sz] = r[sz] = sz;
//        else{
//            l[sz] = l[h[x]];
//            r[sz] = h[x];
//            r[l[h[x]]] = sz;
//            l[h[x]] = sz;
//        }
//    }
//    void remove(int id){
//        for(int i = d[id]; i != id; i = d[i]){
//            l[r[i]] = l[i]; r[l[i]] = r[i];
//        }
//    }
//    void resume(int id){
//        for(int i = u[id]; i != id; i = u[i]){
//            l[r[i]] = r[l[i]] = i;
//        }
//    }
//
//    bool v[N];
//    int f(){
//        int ret = 0;
//        for(int i = r[0]; i != 0; i = r[i]) v[i] = true;
//        for(int i = r[0]; i != 0; i = r[i]){
//            if(v[i]){
//                v[i] = false;
//                ret++;
//                for(int j = d[i]; j != i; j = d[j]){
//                    for(int k = r[j]; k != j; k = r[k]){
//                        v[col[k]] = false;
//                    }
//                }
//            }
//        }
//        return ret;
//    }
//    void dance(int deep){
//
//        if(deep + f() >= cnt) return;
//        if(r[0] == 0){
//            cnt = min(cnt, deep); return;
//        }
//        int id = r[0];
//        for(int i = r[0]; i != 0; i = r[i])
//            if(s[i] < s[id]) id = i;
//
//        for(int i = d[id]; i != id; i = d[i]){
//            remove(i);
//            for(int j = r[i]; j != i; j = r[j]) remove(j);
//            dance(deep + 1);
//            for(int j = l[i]; j != i; j = l[j]) resume(j);
//            resume(i);
//        }
//    }
//}g;
//
//int c[10][10];
//int cover[10][10][1 << 8];
//
//void init()
//{
//    for(int i=1;i<(1<<8);i++)
//    {
//        int n1=0;//计数1的个数,即元素个数
//        int k=0;
//        for(int j=1;(1<<(j-1))<=i;j++)
//            if(i&(1<<(j-1)))
//            {
//                n1++;
//                k=j;
//            }
//        for(;k<=8;k++)
//            cover[k][n1][++c[k][n1]]=i;
//    }
//}
//
//
//int main()
//{
//   // freopen("data.txt", "r", stdin);
//    freopen("out.cpp", "w", stdout);
//    init();
//
//    printf("int ans[9][9][9] = {\n");
//    rep(n, 1, 8) {
//        printf("{");
//        rep(m, 1, n) {
//            printf("\n  {");
//            rep(r, 1, m) {
//                g.init(c[n][m], c[n][r]);
//                rep(i, 1, c[n][m]) rep(j, 1, c[n][r])
//                    if( (cover[n][m][i]&cover[n][r][j]) == cover[n][r][j])
//                        g.link(i, j);
//                g.dance(0);
//                printf("%d%c", g.cnt, r==m?'\0':',');
//            }
//            printf(" },");
//        }
//        printf("\n},\n");
//    }
//
//    printf("};");
//
//    return 0;
//}

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
#define N 10000
#define M 200000
#define MN 5000
#define MM 1034
#define MNN 20000
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

int ans[9][9][9] = {
{
  {1  },
},
{
  {2  },
  {1,1  },
},
{
  {3  },
  {2,3  },
  {1,1,1  },
},
{
  {4  },
  {2,6  },
  {2,3,4  },
  {1,1,1,1  },
},
{
  {5  },
  {3,10  },
  {2,4,10  },
  {2,3,4,5  },
  {1,1,1,1,1  },
},
{
  {6  },
  {3,15  },
  {2,6,20  },
  {2,3,6,15  },
  {2,3,4,5,6  },
  {1,1,1,1,1,1  },
},
{
  {7  },
  {4,21  },
  {3,7,35  },
  {2,5,12,35  },
  {2,3,5,9,21  },
  {2,3,4,5,6,7  },
  {1,1,1,1,1,1,1  },
},
{
  {8  },
  {4,28  },
  {3,11,56  },
  {2,6,14,70  },
  {2,4,8,20,56  },
  {2,3,4,7,12,28  },
  {2,3,4,5,6,7,8  },
  {1,1,1,1,1,1,1,1  },
},
};

int main()
{
    int t, n, m, r;
    scanf("%d", &t);
    rep(Case, 1, t) {
        scanf("%d%d%d", &n, &m, &r);
        printf("Case #%d: %d\n", Case, ans[n - 1][m - 1][r - 1]);
    }
    return 0;
}

Airport HDU - 5046

The country of jiuye composed by N cites. Each city can be viewed as a point in a two- dimensional plane with integer coordinates (x,y). The distance between city i and city j is defined by d ij = |x i - x j| + |y i - y j|. jiuye want to setup airport in K cities among N cities. So he need your help to choose these K cities, to minimize the maximum distance to the nearest airport of each city. That is , if we define d i(1 ≤ i ≤ N ) as the distance from city i to the nearest city with airport. Your aim is to minimize the value max{d i|1 ≤ i ≤ N }. You just output the minimum.
Input
The first line of the input is T (1 ≤ T ≤ 100), which stands for the number of test cases you need to solve.

The first line of each case contains two integers N ,K (1 ≤ N ≤ 60,1 ≤ K ≤ N ),as mentioned above.

The next N lines, each lines contains two integer x i and y i (-10 9 ≤ x i, y i ≤ 10 9), denote the coordinates of city i.
Output
For each test case, print a line “Case #t: ”(without quotes, t means the index of the test case) at the beginning. Then a single integer means the minimum.
Sample Input
2
3 2
0 0
4 0
5 1
4 2
0 3
1 0
3 0
8 9
Sample Output
Case #1: 2
Case #2: 4

二分答案加重复覆盖,本来写的一个代码WA了,原来距离d是要本来就有的。。。。我是枚举的d,就有可能出现枚举出来的d原来不存在的情况。

#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
using namespace std;
typedef pair<long long, long long> P;
typedef long long ll;
#define N 10000
#define M 200000
#define MN 5000
#define MM 1034
#define MNN 20000
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
#define fi first
#define se second
#define rep(i, lll, nnn) for(int i = (lll); i <= (nnn); i++)

struct DLX{
    int col[M], row[M], u[M], l[M], r[M], d[M];
    int n, m, sz, cnt;
    int h[N], s[N];
    void init(int nn, int mm){
        n = nn; m = mm;
        rep(i, 0, m) {
            u[i] = d[i] = i;
            l[i] = i - 1; r[i] = i + 1;
            s[i] = 0;
        }
        l[0] = m; r[m] = 0;
        sz = m;
        rep(i, 0, n) h[i] = -1;
        cnt = INF;
    }
    void link(int x, int y){
        ++sz;
        s[y]++;
        col[sz] = y; row[sz] = x;
        u[sz] = u[y];
        d[sz] = y;
        d[u[y]] = sz;
        u[y] = sz;
        if(h[x] == -1) h[x] = l[sz] = r[sz] = sz;
        else{
            l[sz] = l[h[x]];
            r[sz] = h[x];
            r[l[h[x]]] = sz;
            l[h[x]] = sz;
        }
    }
    void remove(int id){
        for(int i = d[id]; i != id; i = d[i]){
            l[r[i]] = l[i]; r[l[i]] = r[i];
        }
    }
    void resume(int id){
        for(int i = u[id]; i != id; i = u[i]){
            l[r[i]] = r[l[i]] = i;
        }
    }

    bool v[N];
    int f(){
        int ret = 0;
        for(int i = r[0]; i != 0; i = r[i]) v[i] = true;
        for(int i = r[0]; i != 0; i = r[i]){
            if(v[i]){
                v[i] = false;
                ret++;
                for(int j = d[i]; j != i; j = d[j]){
                    for(int k = r[j]; k != j; k = r[k]){
                        v[col[k]] = false;
                    }
                }
            }
        }
        return ret;
    }
    void dance(int deep){

        if(deep + f() >= cnt) return;
        if(r[0] == 0){
            cnt = min(cnt, deep);
            return;
        }
        int id = r[0];
        for(int i = r[0]; i != 0; i = r[i])
            if(s[i] < s[id]) id = i;

        for(int i = d[id]; i != id; i = d[i]){
            remove(i);
            for(int j = r[i]; j != i; j = r[j]) remove(j);
            dance(deep + 1);
            for(int j = l[i]; j != i; j = l[j]) resume(j);
            resume(i);
        }
    }
}g;

int n, k, cnt;
P points[65];
ll d[65][65];
ll dis[N];

bool check(ll mid)
{
    g.init(n, n);
    rep(i, 1, n) rep(j, 1, n) {
        if(d[i][j] <= mid)
            g.link(i, j); //cout << "Ij" <<i <<' ' <<j <<endl;;
    }
    g.dance(0);
   // cout << mid <<' ' << g.cnt << endl;
    return g.cnt <= k;
}

int main()
{
   // freopen("data.txt", "r", stdin);

    int t;
    scanf("%d", &t);
    rep(Case, 1, t) {
        scanf("%d%d", &n, &k);
        rep(i, 1, n) scanf("%lld%lld", &points[i].fi, &points[i].se);

        cnt = 0;
        rep(i, 1, n) rep(j, 1, n){
            d[i][j] = abs(points[i].fi - points[j].fi) + abs(points[i].se - points[j].se);
           // cout << "d " << i << ' ' << j <<' ' << d[i][j] <<endl;
           dis[cnt++] = d[i][j];
        }

        sort(dis, dis + cnt);
        cnt = unique(dis, dis + cnt) - dis;
        int l = 0, r = cnt;
        while(l <= r) {
            ll mid = (r + l) / 2;
          //  cout <<mid <<' ' <<l<<' ' <<r<<endl;
            if(check(dis[mid])) r = mid - 1;
            else l = mid + 1;
            //cout <<mid <<' ' <<l<<' ' <<r<<endl;
        }

        printf("Case #%d: %lld\n", Case, dis[l]);
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值