HOJ 13415 Website Tour(强连通缩点+多重背包dp)

6 篇文章 0 订阅

题意:每个网站有个广告,看这个广告要花t的时间,能得p的分,最多只能看s次,然后给一些网站以及它所能到达的网站,从一个网站到另一个是不花时间的,但是不能停在同一个网站连续不停的看。现在有T的时间,起点任意,问最大得分。

做法:由于都是有向边,所以我们可以把强连通分量缩点了,这其中的点都可以互相到达,再把这些缩后的点给拓扑排序,就是个DAG了,我们就可以dp了,在这个连通分量的点里面就是多重背包了,可以用二进制分解的办法做到每个点Tlogk的复杂度。然后再去更新它之后的点即可。总复杂度o(n*T*logk+m)。

AC代码:

#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<string.h>
#include<string>
#include<sstream>
#include<bitset>
using namespace std;
#define ll __int64
#define ull unsigned __int64
#define eps 1e-8
#define NMAX 1000000000
#define MOD (1<<30)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1)
template<class T>
inline void scan_d(T &ret)
{
    char c;
    int flag = 0;
    ret=0;
    while(((c=getchar())<'0'||c>'9')&&c!='-');
    if(c == '-')
    {
        flag = 1;
        c = getchar();
    }
    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
    if(flag) ret = -ret;
}
const int maxn = 100+10;
const int maxm = 1000+10;
struct Edge
{
    int v,next;
}e[2][maxm];
int head[2][maxn], ecnt[2];
void add_edge(int u, int v, int d)
{
    e[d][ecnt[d]].v = v; e[d][ecnt[d]].next = head[d][u];
    head[d][u] = ecnt[d]++;
}
struct node
{
    int p,t,k;
    node(){}
    node(int _p, int _t, int _k):p(_p),t(_t),k(_k){}
}no[maxn];
bool zi[maxn];

int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt, tp;
int S[maxn];
void dfs(int u)
{
    pre[u] = lowlink[u] = ++dfs_clock;
    S[++tp] = u;
    for(int i = head[0][u]; ~i; i = e[0][i].next)
    {
        int v = e[0][i].v;
        if(!pre[v])
        {
            dfs(v);
            lowlink[u] = min(lowlink[u],lowlink[v]);
        }
        else if(!sccno[v]) lowlink[u] = min(lowlink[u],pre[v]);
    }
    if(lowlink[u] == pre[u])
    {
        scc_cnt++;
        while(1)
        {
            int x = S[tp]; tp--;
            sccno[x] = scc_cnt;
            if(x == u) break;
        }
    }
}

void find_scc(int n)
{
    tp = -1;
    dfs_clock = scc_cnt = 0;
    memset(sccno,0,sizeof(sccno));
    memset(pre,0,sizeof(pre));
    for(int i = 1; i <= n; i++) if(!pre[i])
        dfs(i);
}

vector<int>vec[105];

int Em[maxm][2];
bool bian[maxn][maxn];
int in[maxn],top[maxn];
void topo(int n)
{
    queue<int>q;
    for(int i = 1; i <= n; i++) if(in[i] == 0)
        q.push(i);
    int k = 1;
    while(!q.empty())
    {
        int x = q.front(); q.pop();
        top[k++] = x;
        for(int i = head[1][x]; ~i ; i = e[1][i].next)
        {
            int v = e[1][i].v;
            in[v]--;
            if(in[v] == 0) q.push(v);
        }
    }
}
int dp[maxn][10000+10];

node ha[maxn];
int main()
{
#ifdef GLQ
    freopen("input.txt","r",stdin);
//    freopen("o.txt","w",stdout);
#endif
    int n,m,T;
    while(~scanf("%d%d%d",&n,&m,&T) && n+m+T)
    {
        memset(head,-1,sizeof(head));
        memset(ecnt,0,sizeof(ecnt));
        memset(zi,0,sizeof(zi));
        for(int i = 1; i <= n; i++)
            scanf("%d%d%d",&no[i].p,&no[i].t,&no[i].k);
        for(int i = 1; i <= m; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            if(u == v)
            {
                zi[u] = 1;
                Em[i][0] = -1;
            }
            else
            {
                Em[i][0] = u;
                Em[i][1] = v;
                add_edge(u,v,0);
            }
        }
        find_scc(n);
        for(int i = 1; i <= scc_cnt; i++) vec[i].clear();
        for(int i = 1; i <= n; i++)
        {
            vec[sccno[i]].push_back(i);
        }
        for(int i = 1; i <= scc_cnt; i++) if(vec[i].size() == 1 && zi[vec[i][0]] == 0)
            no[vec[i][0]].k = 1;
        memset(bian,0,sizeof(bian));
        memset(in,0,sizeof(in));
        for(int i = 1; i <= m; i++) if(Em[i][0] != -1)
        {
            int u = sccno[Em[i][0]], v = sccno[Em[i][1]];
//            cout<<u<<" "<<v<<endl;
            if(u != v && bian[u][v] == 0)
            {
                bian[u][v] = 1;
                in[v]++;
                add_edge(u,v,1);
            }
        }
        topo(scc_cnt);
        for(int i = 1; i <= scc_cnt; i++)
            for(int j = 0; j <= T; j++)
                dp[i][j] = 0;
        for(int i = 1; i <= scc_cnt; i++)
        {
            int pos = top[i];
            int sz = vec[pos].size();
            for(int j = 0; j < sz; j++)
            {
                int id = vec[pos][j];
                if(no[id].k*no[id].t >= T)
                {
                    for(int v = no[id].t; v <= T; v++)
                        dp[pos][v] = max(dp[pos][v],dp[pos][v-no[id].t]+no[id].p);
                    continue;
                }
                int cnt = 0;
                while((1<<cnt+1)-1 < no[id].k)
                {
                    ha[cnt] = node((1<<cnt)*no[id].p, (1<<cnt)*no[id].t, (1<<cnt));
                    cnt++;
                }
                int tt = no[id].k-(1<<cnt)+1;
                ha[cnt++] = node(tt*no[id].p, tt*no[id].t, tt);
                for(int k = 0; k < cnt; k++)
                {
                    for(int v = T; v >= ha[k].t; v--)
                        dp[pos][v] = max(dp[pos][v],dp[pos][v-ha[k].t]+ha[k].p);
                }
            }
            for(int j = head[1][pos]; ~j; j = e[1][j].next)
            {
                int v = e[1][j].v;
                for(int val = 0; val <= T; val++)
                    dp[v][val] = max(dp[v][val],dp[pos][val]);
            }
        }
        int ans = 0;
        for(int i = 1; i <= scc_cnt; i++)
            ans = max(ans,dp[i][T]);
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值