XMU 1617 刘备闯三国之汉中之战 【BFS+染色】

37 篇文章 1 订阅
23 篇文章 0 订阅

1617: 刘备闯三国之汉中之战

Time Limit: 1000 MS   Memory Limit: 128 MB
Submit: 6   Solved: 5
[ Submit][ Status][ Web Board]

Description

        刘备(161年-223年6月10日),字玄德,东汉末年幽州涿郡涿县,西汉中山靖王刘胜的后代。刘备一生极具传奇色彩,早年颠沛流离、备尝艰辛最终却凭借自己的谋略终成一方霸主。那么在那个风云激荡的年代,刘备又是如何从一个卖草鞋的小人物一步一步成为蜀汉的开国皇帝呢?让我们一起拨开历史的迷雾,还原一个真实的刘备。

       建安二十二年,刘备与曹操争夺汉中,展开了一场大战。

       刘备的军队有n(1<=n<=200000)个营寨,营寨之间有m条道路相连(1<=m<=200000),刘备想在一些营寨上放置一些装备。由于装备有限且不同的道路重要程度不一样,有些道路连接的2个营寨都要放装备,有的道路只要在其连接的两个营寨之一放置装备即可,有的道路连接的两个营寨都不需要放置装备。

        如何在满足条件下,放置最少的装备又是一个头疼的问题。当然,由于之前的出色发挥,现在已经晋升为大内总管的你,是时候证明你自己配得上这个职位了。

Input

 第一行包含两个整数n,m。

接下来m行,每行有3个整数a,b,c.

    a,b表示营寨a和b之间有一条道路(1<=a,b<=n);

    c为0,或1或2。表示这条道路两边的营寨应该恰好选择c个放置装备。

Output

 如果存在满足要求的方案,输出最少需要放置装备的数量。

否则输出impossible。

Sample Input

样例一:
4 4
1 2 2
2 3 1
3 4 1
4 1 2

样例二:
5 5
1 2 1
2 3 1
2 4 1
2 5 1
4 5 1

Sample Output

样例一:
3

样例二:
impossible

HINT

Source

[ Submit][ Status][ Web Board]

题目链接:

  http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1617

题目大意:

  N个点,M条边,每条边都有一个要求军械库数量C(0 1 2),表示这条边的两个端点的军械库数量和为C,且每个端点最多放1个军械库。

  问是否能够满足军械库放置要求,能满足的话输出最小的军械库数量。

题目思路:

  【BFS+染色】

  因为每个点只能有或没有军械库。将军械库视为标记。首先由于是无向图所以存在若干联通块。

  可以枚举每个联通块的其中一个点有还是没有标记,并用这个点去拓展这个点的联通块并01染色(这个点所能到达的所有点)

  初始点标记为0需要的标记数为sum0,初始点为1的标记数为sum1,选取0 或1 能够满足的加到答案,如果0 1染色都能够满足图的要求就取min。

  在BFS的过程中只要有一个节点同时不满足0和1染色则无解。

  每个点只会被走过一次,所以是O(N)的。



/****************************************************
     
    Author : Coolxxx
    Copyright 2017 by Coolxxx. All rights reserved.
    BLOG : http://blog.csdn.net/u010568270
     
****************************************************/
#include<bits/stdc++.h>
#pragma comment(linker,"/STACK:1024000000,1024000000")
#define abs(a) ((a)>0?(a):(-(a)))
#define lowbit(a) (a&(-a))
#define sqr(a) ((a)*(a))
#define mem(a,b) memset(a,b,sizeof(a))
const double EPS=1e-8;
const int J=10;
const int MOD=100000007;
const int MAX=0x7f7f7f7f;
const double PI=3.14159265358979323;
const int N=200004;
using namespace std;
typedef long long LL;
double anss;
LL aans;
int cas,cass;
int n,m,lll,ans;
int q[N],last[N];
int mark[N][2];
bool u[N];
struct xxx
{
    int next,to,d;
}a[N+N];
void add(int x,int y,int z)
{
    a[++lll].to=y;
    a[lll].d=z;
    a[lll].next=last[x];
    last[x]=lll;
}
bool spfa(int s)
{
    int i,l=0,r=1,now,to,sumz=0,sumo=0;
    bool z=0,o=0;
    q[1]=s;mark[s][0]=0,mark[s][1]=1;u[s]=1;
    while(l!=r)
    {
        now=q[l=(l+1)%N];
        sumz+=mark[now][0];sumo+=mark[now][1];
        for(i=last[now];i;i=a[i].next)
        {
            to=a[i].to;
            if(mark[to][0]==-1)mark[to][0]=a[i].d-mark[now][0];
            if(mark[to][1]==-1)mark[to][1]=a[i].d-mark[now][1];
            if(mark[now][0]+mark[to][0]!=a[i].d || mark[to][0]<0 || mark[to][0]>1)z=1;
            if(mark[now][1]+mark[to][1]!=a[i].d || mark[to][1]<0 || mark[to][1]>1)o=1;
            if(!u[to])
            {
                u[to]=1;
                q[r=(r+1)%N]=to;
            }
        }
        if(z && o)break;
    }
    if(z && o)return 0;
    if(!z && o)ans+=sumz;
    else if(z && !o)ans+=sumo;
    else if(!z && !o)ans+=min(sumz,sumo);
    return 1;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("1.txt","r",stdin);
//  freopen("2.txt","w",stdout);
    #endif
    int i,j,k;
    int x,y,z;
//  for(scanf("%d",&cass);cass;cass--)
//  for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
//  while(~scanf("%s",s))
    while(~scanf("%d",&n))
    {
        mem(u,0);mem(mark,-1);
        scanf("%d",&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        ans=0;
        for(i=1;i<=n;i++)
        {
            if(u[i])continue;
            if(!spfa(i))break;
        }
        if(i<=n)puts("impossible");
        else printf("%d\n",ans);
    }
    return 0;
}
/*
//
 
//
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值