【bzoj 2260】商店購物 & 【bzoj 4349】最小樹形圖 (朱劉算法)

傳送門biu~biu~
只需要考慮第一次購買的順序,然後剩下需要買的都按最小价格買。設一個虛擬節點0,原價購買i物品就從0向i連邊,u對v有優惠關係就從u向v連邊。跑朱劉算法即可。

#include <bits/stdc++.h>
#define N 105
#define M 10005
#define inf 1e30
using namespace std;
int n,k,v,m,pre[N],id[N],vis[N],b[N];
double a[N],low[N],in[N],ans;
struct edge{
    int u,v;double w;
    edge(){}
    edge(int u,int v,double w):u(u),v(v),w(w){}
}e[M];
void add(int u,int v,double w){e[m++]=edge(u,v,w);}
double zhuliu(int rt) {
    double ret=0;
    while(1){
        for(int i=0;i<v;++i) in[i]=inf,id[i]=-1,vis[i]=-1;
        for(int i=0;i<m;++i){
            int u=e[i].u,v=e[i].v;double w=e[i].w;
            if(w<in[v] && v!=u) pre[v]=u,in[v]=w;
        }
        in[rt]=0;pre[rt]=rt;
        for(int i=0;i<v;++i){
            if(in[i]==inf) return -1;
            ret+=in[i];
        }
        int num=0;
        for(int i=0;i<v;++i){
            int u=i;
            while(vis[u]==-1) vis[u]=i,u=pre[u];
            if(vis[u]!=i || u==rt) continue;
            for(int t=pre[u];t!=u;t=pre[t]) id[t]=num;
            id[u]=num++;
        }
        if (num==0) break;
        for(int i=0;i<v;++i) if(id[i]==-1) id[i]=num++;
        for(int i=0;i<m;++i) e[i].w-=in[e[i].v],e[i].u=id[e[i].u],e[i].v=id[e[i].v];
        v=num;  rt=id[rt];
    }
    return ret;
}
int main(){
    scanf("%d",&n);v=n+1;
    for(int i=1;i<=n;++i){
        scanf("%lf%d",&a[i],&b[i]),low[i]=a[i];
        if(b[i])    add(0,i,a[i]);
        else    add(0,i,0);
    }
    scanf("%d",&k);
    for(int i=1;i<=k;++i){
        int u,v;double w;
        scanf("%d%d%lf",&u,&v,&w);
        if(b[u] && b[v]){
            add(u,v,w);
            low[v]=min(low[v],w);
        }
    }
    ans=zhuliu(0);
    for(int i=1;i<=n;++i)    if(b[i])    ans+=low[i]*(b[i]-1);
    printf("%.2lf",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章