Luogu P2002 消息擴散&&P1262 間諜網絡

怕本身過久沒寫Tarjan了就會把這種神仙算法忘掉。算法

其實這種類型的圖論題的套路仍是比較簡單且顯然的。網絡

P2002 消息擴散

很顯然的題目,由於在一個環(其實就是強連通份量)中的城市都只須要讓其中一個知道就可讓其它的城市都得知信息了。spa

所以咱們把在一個強連通份量中的點都縮點,而後就獲得一個DAGcode

而後咱們只須要給入度爲0的點傳遞信息便可string

CODEio

#include<cstdio>
#include<cstring>
using namespace std;
const int N=100005;
struct edge
{
    int to,next;
}e[N*5];
int head[N],col[N],ru[N],dfn[N],low[N],stack[N],n,m,x,y,cnt,tot,top,sum,ans;
bool vis[N];
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch=tc();
    while (ch<'0'||ch>'9') ch=tc();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
inline void add(int x,int y)
{
    e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;
}
inline int min(int a,int b)
{
    return a<b?a:b;
}
inline void Tarjan(int now)
{
    dfn[now]=low[now]=++tot; stack[++top]=now; vis[now]=1;
    for (register int i=head[now];i^-1;i=e[i].next)
    if (!dfn[e[i].to])
    {
        Tarjan(e[i].to);
        low[now]=min(low[now],low[e[i].to]);
    } else if (vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]);
    if (!(low[now]^dfn[now]))
    {
        col[now]=++sum; vis[now]=0;
        while (stack[top]!=now)
        {
            col[stack[top]]=sum; vis[stack[top--]]=0;
        } --top;
    }
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    memset(head,-1,sizeof(head));
    memset(e,-1,sizeof(e));
    register int i,j; read(n); read(m);
    for (i=1;i<=m;++i)
    read(x),read(y),add(x,y);
    for (i=1;i<=n;++i)
    if (!dfn[i]) Tarjan(i);
    for (i=1;i<=n;++i)
    for (j=head[i];j^-1;j=e[j].next)
    if (col[i]^col[e[j].to]) ++ru[col[e[j].to]];
    for (i=1;i<=sum;++i)
    if (!ru[i]) ++ans;
    printf("%d",ans);
    return 0;
}

P1262 間諜網絡

這個的話讀一下題目就能夠發現這是前一題的加權版class

而後對於一個強連通份量中的點,在縮點後的權值應該是多少呢。next

很顯然,確定找最便宜的人賄賂嗎!static

因此咱們上一題的操做之上加權而後仍是找入度爲0的點。top

不過注意下若是一個點的入度爲0可是這個間諜沒法被賄賂那麼就沒法被控制

CODE

#include<cstdio>
#include<cstring>
using namespace std;
const int N=3005,M=8005;
struct edge
{
    int to,next;
}e[M];
int head[N],col[N],ru[N],dfn[N],low[N],stack[N],a[N],s[N],num[N],n,m,x,y,cnt,tot,top,sum,ans,INF,p;
bool vis[N];
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch=tc();
    while (ch<'0'||ch>'9') ch=tc();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
inline void add(int x,int y)
{
    e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;
}
inline int min(int a,int b)
{
    return a<b?a:b;
}
inline void Tarjan(int now)
{
    dfn[now]=low[now]=++tot; stack[++top]=now; vis[now]=1;
    for (register int i=head[now];i^-1;i=e[i].next)
    if (!dfn[e[i].to])
    {
        Tarjan(e[i].to);
        low[now]=min(low[now],low[e[i].to]);
    } else if (vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]);
    if (!(low[now]^dfn[now]))
    {
        col[now]=++sum; s[sum]=a[now]; num[sum]=now; vis[now]=0;
        while (stack[top]!=now)
        {
            col[stack[top]]=sum; vis[stack[top]]=0;
            s[sum]=min(s[sum],a[stack[top--]]);
        } --top;
    }
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    memset(head,-1,sizeof(head));
    memset(e,-1,sizeof(e));
    memset(a,127,sizeof(a)); INF=a[0];
    register int i,j; read(n); read(p);
    for (i=1;i<=p;++i)
    read(x),read(y),a[x]=y;
    for (read(m),i=1;i<=m;++i)
    read(x),read(y),add(x,y);
    for (i=1;i<=n;++i)
    if (!dfn[i]) Tarjan(i);
    for (i=1;i<=n;++i)
    for (j=head[i];j^-1;j=e[j].next)
    if (col[i]^col[e[j].to]) ++ru[col[e[j].to]];
    for (i=1;i<=sum;++i)
    if (!ru[i])
    {
        if (!(s[i]^INF)) { printf("NO\n%d",num[i]); return 0; }
        ans+=s[i];
    }
    printf("YES\n%d",ans);
    return 0;
}
相關文章
相關標籤/搜索