码迷,mamicode.com
首页 > 其他好文 > 详细

(贪心)NOIP模拟题:引爆炸弹

时间:2014-10-27 09:26:10      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:贪心   强连通   生成森林   

是否有环往往很大程度上影响着一道关于图的问题。

描述 Description(Time Limit: 1s ; Memory Limit 128MB)

有n个炸弹,有些炸弹牵了一根单向引线(也就是说引线只有在这一端能被炸弹点燃),只要引爆了这个炸弹,用引线连接的下一个炸弹也会爆炸。每个炸弹还有个得分,当这个炸弹被引爆后就能得到相应得分。

现在要你引爆k个炸弹,使得分最大。

输入格式 InputFormat

第1行两个整数n、k。

接下来n行每行两个整数a[i]、b[i]。a[i]表示这个炸弹用引线连接的下一个炸弹,如果a[i]为0,则表示这个炸弹没连接引线。b[i]表示这个炸弹的得分。

输出格式 OutputFormat

仅一个数,表示最大得分。

样例输入 SampleInput  

8 2

0 1

1 1

2 100

2 100

0 1

5 1

6 2

6 2

样例输出 SampleOutput 

202

数据范围和注释 Hint

1≤b[i]≤1000000

对于30%的数据,n≤1000 k≤30

对于60%的数据,n≤50000 k≤100

对于100%的数据,n≤200000 k≤500

这个题有没有环呢?

我们的数据里没有。

因此就可以预处理出所有 叶子节点 的最大连锁爆炸值,然后降序排序;

接着按顺序对每个连锁爆炸进行处理:如果它的连锁爆炸过程中有之前已经爆炸过的炸弹,就减掉这颗炸弹的爆炸值;否则把这颗炸弹标记为已爆炸。

然后再排一遍序,从大到小记录k个值的和,输出即可。(要开long long 啊)

<span style="font-size:18px;"><strong>#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
int n,k;

struct zhadan
{
	int w,next;
}b[200010];
struct defen
{
	int i;
	long long fen;
	friend bool operator < (defen a,defen b)
	{
		return a.fen>b.fen;
	}
}s[200010];

long long dfs(int x)
{
	if(x==0) return 0;
	if(s[x].fen>0) return s[x].fen;
	int ne=b[x].next;
	return s[x].fen=b[x].w+dfs(ne);
}

bool vis[200010];

int main()
{
	freopen("bomb.in","r",stdin);
	freopen("bomb.out","w",stdout);
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) 
	{
		scanf("%d%d",&b[i].next,&b[i].w);
		s[i].i=i;
	}
	for(int i=1;i<=n;i++) dfs(i);
	sort(s+1,s+n+1);
	int u,ne;
	for(int i=1;i<=n;i++)
	{
		u=s[i].i;
		ne=b[u].next;
		if(vis[u]) s[i].fen-=b[u].w;
		vis[u]=1;
		while(ne!=0)
		{
			if(vis[ne]) s[i].fen-=b[ne].w;
			vis[ne]=1;
			ne=b[ne].next;
		}
	}
	sort(s+1,s+n+1);
	long long ans=0;
	for(int i=1;i<=k;i++) ans+=s[i].fen;
	printf("%I64d\n",ans);
	return 0;
}</strong></span>
当然,如果有环的话就要涉及到缩点了(喜(sang)闻(xin)乐(bing)见(kuang))。

<span style="font-size:18px;color:#009900;"><strong style="background-color: rgb(255, 102, 102);">#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
//注意一个炸弹可能被多个导线引爆,但是最多引爆下一个炸弹,这个可能很关键
//那么如果倒过来建图,就是一个森林
//建图的时候似乎可以缩边优化
//如果有环,直接缩点,并且缩点完了一定是根
//贪心一定是对的,每次选一条树上的最长路,Bomb!

//Global Variables
int n,k;
int w[200010];
//End Global Variables  template<typename _Tp>

//Map
namespace MAP{
int h[200010];

struct edge
{
    int v,next;
}e[200010];

int ecnt = -1;
inline void adde(int u,int v)
{
    ecnt++;
    e[ecnt].v = v;
    e[ecnt].next = h[u];
    h[u] = ecnt;
}

inline void reset()
{
    memset(h,-1,sizeof(h));
    ecnt = -1;
}
}
//End Map

//Tree
namespace TREE{
using namespace MAP;
//Variables
    //左儿子右兄弟
    struct node
    {
        int num;
        int l,r,f;
        long long maxpathsum;
        int maxpathson;
        long long w;

        node(int num = -1,int f = -1,long long w = 0,int l = -1,int r = -1):num(num),f(f),w(w),l(l),r(r){}
        int Addson(long long w);
        void Setson(int n);
        long long maxpath();
        void Del();

        void _DFS();
    }T[200010];

    int Tcnt = 0;
    int node::Addson(long long w)
    {
        T[Tcnt] = node(Tcnt,this -> num,w,-1,-1);
        this -> Setson(Tcnt);
        return Tcnt++;
    }

    void node::Setson(int n)
    {
        T[n].f = this -> num;
        if(this -> l == -1)
        {
            this -> l = n;
        }else{
            int i = this -> l;
            for(;T[i].r != -1;i = T[i].r);

            T[i].r = n;
        }
    }

    long long node::maxpath()
    {
        long long rv = 0;

        this -> maxpathson = -1;
        if(this -> l == -1)
        {
           // PRINT("maxpath[%d] = %lld\n",this -> num,this -> w);
            return this -> maxpathsum = this -> w;
        }else{
            for(int i = this -> l;i != -1;i = T[i].r)
            {
                T[i].maxpath();
                if(T[i].maxpathsum > rv)
                {
                    rv = T[i].maxpathsum;
                    this -> maxpathson = i;
                }
            }
            //PRINT("maxpath[%d] = %lld\n",this -> num,rv + this -> w);
            return this -> maxpathsum = (rv + this -> w);
        }
    }

struct gr
{
    bool
    operator()(int & _x,int & _y) const
    { return T[_x].maxpathsum < T[_y].maxpathsum; }
};
priority_queue<int,vector<int>,gr>roots;

    void node::Del()
    {
        for(int i =this -> l;i != -1;i = T[i].r)
        {
            if(i == this->maxpathson)
            {
                T[i].Del();
            }else{
                roots.push(i);
            }
        }
    }

    void node::_DFS()
    {
        //PRINT("%d\n",this -> num);

        for(int i = this -> l;i != -1;i = T[i].r)
        {
            T[i]._DFS();
        }

        //PRINT("~%d\n",this -> num);
    }
//End Variables
//Functions
//建树
int vis[200010];
int cn[200010];
int isroot[200010];

void DFS(int u,int vn,int & is_circle)
{
    //PRINT("%d %d\n",u,cn[u]);
    vis[u] = vn;

    int sub_circle = 0;
    int thi_circle = 0;
    for(int i = h[u];i != -1;i = e[i].next)
    {
        int v = e[i].v;
        if(vis[v])
        {
            if(vis[v] == vn)
            {
                //成环了
                thi_circle = 1;
            }else{
                //连上一个访问过的子树,则子树的根一定不是缩出来的点
                T[cn[u]].Setson(cn[v]);
                isroot[cn[v]] = 0;
            }
        }else{
            cn[v] = T[cn[u]].Addson(w[v]);
            isroot[cn[v]] = 0;
            DFS(v,vn,sub_circle);

            if(sub_circle)
            {
                if(T[cn[u]].l == cn[v])
                {
                    T[cn[u]].l = T[cn[v]].r;
                }else{
                    for(int i = T[cn[u]].l;i != -1;i = T[i].r)
                    {
                        if(T[i].r == cn[v])
                        {
                            T[i].r = T[cn[v]].r;
                            break;
                        }
                    }
                }
            }

        }
    }

    if((sub_circle || thi_circle) && isroot[cn[u]] == 0)
    {
        //PRINT("merge %d\n",u);
        is_circle = 1;
        //Merge to father
        int f = T[cn[u]].f;
        if(T[cn[u]].l != -1)
        {
            T[f].Setson(T[cn[u]].l);
            for(int i = T[cn[u]].l;i != -1;i = T[i].r)
            {
                T[i].f = f;
            }
        }

        T[f].w += T[cn[u]].w;
    }
}

void Build()
{
    memset(vis,0,sizeof(vis));

    for(int ii = 0;ii < 200010;ii++){
        isroot[ii] = 1;
    }

    for(int i = 1;i <= n;i++)if(!vis[i])
    {
        int temp;
        cn[i] = Tcnt++;
        T[cn[i]] = node(cn[i],-1,w[i]);
        DFS(i,i,temp);
    }

    for(int i = 0;i < Tcnt;i++)if(isroot[i])
    {
        T[i].maxpath();
        //T[i]._DFS();
        roots.push(i);
    }
}
//初始化计算
void Init()
{
    return;
}
//一次贪心
long long Do()
{
    int u = roots.top();roots.pop();
    T[u].Del();
//PRINT("choose %d %lld\n",u,T[u].maxpathsum);
    return T[u].maxpathsum;

    Init();
}
}
//End Tree

//Main Structure
inline void ir()
{
    freopen("bomb.in","r",stdin);
    freopen("bomb.out","w",stdout);

    scanf("%d%d",&n,&k);

    MAP::reset();
    int a;
    for(int i = 1;i <= n;i++)
    {
        scanf("%d%d",&a,&w[i]);
        //反向加边
        MAP::adde(a,i);
    }
}

int main()
{
    ir();

    TREE::Build();
    TREE::Init();

    long long ans = 0;
    for(int i = 0;i <k;i++)
    {
        ans += TREE::Do();
    }

    cout << ans << '\n';
    return 0;
}</strong></span><span style="font-size:14px;">
</span>




(贪心)NOIP模拟题:引爆炸弹

标签:贪心   强连通   生成森林   

原文地址:http://blog.csdn.net/u011500508/article/details/40481345

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!