HDU 4293 Groups

  每個有效的(A,B),都能對應到一個group的區間[A+1,N-B]。把每個group看作一個節點,權值爲這個group的player出現的次數(且不能超過區間長度)。若兩個區間不衝突,從左邊的區間向右邊的連一條有向邊。加上源點和終點(連上所有節點),求最長路。

//2012-09-16 18:56:27	Accepted	4293	156MS	2260K	1900 B	G++	Aros
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN = 500+5, MAXM = 300000+5;
const int INF = 0x3f3f3f3f;
int N, a, b, A[MAXN], B[MAXN];
int n, s, t, mp[MAXN][MAXN];
int val[MAXN], d[MAXN];
int e, head[MAXN], next[MAXM], v[MAXM];
bool inq[MAXN];
queue<int> Q;
void addedge(int x, int y)
{
    v[e] = y;
    next[e] = head[x]; head[x] = e++;
}
void spfa()
{
    for (int i = 1; i <= n; i++)
        d[i] = 0;
    memset(inq, 0, sizeof(inq));
    Q.push(s);
    while (!Q.empty())
    {
        int u = Q.front(); Q.pop();
        inq[u] = 0;
        for (int i = head[u]; i != -1; i = next[i])
            if (d[v[i]] < d[u]+val[v[i]])
            {
                d[v[i]] = d[u]+val[v[i]];
                if (!inq[v[i]])
                {
                    Q.push(v[i]);
                    inq[v[i]] = 1;
                }
            }
    }
}
int main()
{
    while (scanf("%d", &N) != EOF)
    {
        e = 0; n = 0;
        memset(head, -1, sizeof(head));
        memset(mp, 0, sizeof(mp));
        memset(val, 0, sizeof(val));
        for (int i = 1; i <= N; i++)
        {
            scanf("%d%d", &a, &b);
            if (a+b >= N)
                continue;
            int x = a+1, y = N-b, &m = mp[x][y];
            if (!m)
            {
                m = ++n;
                A[m] = x;
                B[m] = y;
            }
            val[m] = min(B[m]-A[m]+1, val[m]+1);
        }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (B[i] < A[j])
                    addedge(i, j);
        s = n+1, t = n+2; val[s] = val[t] = 0;
        for (int i = 1; i <= n; i++)
            addedge(s, i), addedge(i, t);
        n += 2;
        spfa();
        printf("%d\n", d[t]);
    }
    return 0;
}


  更新dp解法,d[i]表示長度爲i且包含以I結尾的區間時最大的人數。

//2012-09-20 16:05:55	Accepted	4293	46MS	1224K	1178 B	G++	Aros
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 500+5;
const int INF = 0x3f3f3f3f;
int N, a, b, A[MAXN], B[MAXN], r[MAXN];
int mp[MAXN][MAXN], num[MAXN], d[MAXN];
bool cmp(const int a, const int b)
{
    return B[a] < B[b];
}
int main()
{
    while (scanf("%d", &N) != EOF)
    {
        memset(mp, 0, sizeof(mp));
        memset(num, 0, sizeof(num));
        memset(d, 0, sizeof(d));
        int n = 0, ans = 0;
        for (int i = 1; i <= N; i++)
        {
            scanf("%d%d", &a, &b);
            if (a+b >= N)
                continue;
            int &m = mp[a+1][N-b];
            if (!m)
            {
                m = ++n;
                A[n] = a+1;
                B[n] = N-b;
                r[n] = n;
            }
            num[m] = min(num[m]+1, N-a-b);
        }
        sort(r+1, r+1+n, cmp);
        for (int i = 1; i <= n; i++)
            for (int j = 0; j < A[r[i]]; j++)
                d[B[r[i]]] = max(d[B[r[i]]], d[j]+num[r[i]]);
        for (int i = 1; i <= N; i++)
            ans = max(ans, d[i]);
        printf("%d\n", ans);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章