周練

CF701E
思路:這是第一次對於貢獻這兩個字有了一定的理解。
易得:每條邊經過的次數=min(這條邊左邊學校個數,這條邊右邊需要的學校個數),爲了能夠達到最大,就儘量能走的邊都走一遍,也就是把所有邊對於答案的貢獻加起來;此處看來,貢獻彷彿就是可以對答案產生影響但又不一定必須要選擇

int n,k,mark[maxn],cnt,head[maxn],vis[maxn],val[maxn];
ll ans=0;
struct Edge
{
    int v,next;
}edge[maxn<<1];
void add_edge(int u,int v)
{
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void Initial()
{
    memset(val,0,sizeof(val));
    memset(head,-1,sizeof(head));
    memset(mark,0,sizeof(mark));
    memset(edge,0,sizeof(edge));
    cnt=0;ans=0;
}
void dfs(int now)
{
    if(vis[now])
        return ;
    //printf("now=%d,ans=%d\n",now,ans);
    vis[now]=1;
    if(mark[now])
        val[now]=1;
    for(int i=head[now];~i;i=edge[i].next)
    {
        int v=edge[i].v;
        if(vis[v])
            continue ;
        dfs(v);
        val[now]+=val[v];
        //printf("vnow=%d,vv=%d\n",val[now],val[v]);
    }
    ans+=(ll)min(val[now],2*k-val[now]);
    vis[now]=0;
}
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        Initial();
        for(int i=1;i<=k*2;i++)
        {
            int tmp;
            scanf("%d",&tmp);
            mark[tmp]=1;
        }
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
        }
        dfs(1);
        printf("%lld\n",ans);
    }
    return 0;
}

poj1988(節點帶權值的並查集)
思路:我們要查詢經過一系列操作後某個方塊下的個數,就直接維護每個方塊下的方塊個數,但是要順帶維護樹的節點的個數,
在這裏插入圖片描述
如圖標出的是節點權值
首先是Find函數,直接更新即可,比如樣例中2那一坨放到6上面後,2的權值還未更新,仍是1。使用find函數吧途徑節點的權值全部加起來。
然後是Union函數,一開始2和4位於同一顆樹上,6和1位於同一個樹上,大小均爲2,將f[4]改爲6時,val[4]+=size[6],也就是加上父節點所在樹的大小(=2);同時父節點的大小也要更新,因爲多了一棵子樹。

//直接主函數
int p,siz[maxn],f[maxn],val[maxn];
void Initial()
{
    for(int i=1;i<=p;i++)
    {
        f[i]=i;
        val[i]=0;
        siz[i]=1;
    }
}
int myfind(int x)
{
   // printf("mfind: x=%d\n",x);
    if(x==f[x])
        return f[x];
    int tmp=f[x];
    f[x]=myfind(f[x]);
    val[x]+=val[tmp];
    return x=f[x];
}
void Union(int x,int y)
{
    int fx=myfind(x);
    //printf("heh\n");
    int fy=myfind(y);
    //printf("fx=%d,fy=%d\n",fx,fy);
    if(fx!=fy)
    {
       // printf("fx=%d.fy=%d\n",fx,fy);
        f[fx]=fy;
        val[fx]+=siz[fy];
        siz[fy]+=siz[fx];
    }
}
int main()
{
    scanf("%d",&p);
    Initial();
    while(p--)
    {
        char ch;
        cin>>ch;
        if(ch=='M')
        {
            int x,y;
            scanf("%d%d",&x,&y);
            Union(x,y);
        }
        else if(ch=='C')
        {
            int x;
            scanf("%d",&x);
           // printf("val=%d\n",val[x]);
            int fx=myfind(x);
            printf("%d\n",val[x]);
        }
    }
    return 0;
}

hdu1811(拓撲排序+並查集)
思路:先處理相等的關係,將所有相等的點看成一點,不影響排序的結果,然後再利用拓撲排序看是否能排出一個序列出來,這一點我之前學習的時候沒有注意到
1.若進入隊列的點數小於總的點的數量,則必定存在環;等於則是一個無環圖。
2.若隊列中的點的數量大於了1,那麼此時處於隊列中的點之間的關係是不確定的。
代碼:

int n,m,f[maxn],in[maxn],flag;
vector<int>v[maxn];
string ans[4];
struct STR
{
    int a,b;
    char ch;
}str[maxn*2];
int Find(int x)
{
    if(f[x]==x)
        return f[x];
    return f[x]=Find(f[x]);
}
void Initial()
{
    flag=1;
    for(int i=1;i<=n;i++)
    {
        v[i].clear();
        f[i]=i;
        in[i]=0;
    }
}
void tp()
{
    queue<int>q;
    while(!q.empty()) q.pop();
    int cnt=0,num=0;
    //printf("fi=%d\n",Find(1));
    for(int i=1;i<=n;i++)
    {
        if(f[i]==i)
        {
            num++;
            if(in[i]==0)
            {
            //printf("fi=%d\n",fi);
                q.push(i);
            }
        }

    }
    while(!q.empty())
    {
        if(q.size()>=2)
        {
            flag=2;
        }
        int u=q.front();q.pop();cnt++;//printf("u=%d,cn=%d\n",u,v[u].size());
        for(int i=0;i<v[u].size();i++)
        {
            int to=v[u][i];
            //printf("t=%d,to=%d\n",t,to);
            in[to]--;
            if(in[to]==0)
            {
                q.push(to);
            }
        }
    }
  // printf("cbnt=%d\n",cnt);
    if(cnt<num)
        flag=3;
}
int main()
{
     ans[1]=ans[1]+"OK";
    ans[2]=ans[2]+"UNCERTAIN";
    ans[3]=ans[3]+"CONFLICT";
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        Initial();
        flag=1;
        for(int i=1;i<=m;i++)
        {
            cin>>str[i].a>>str[i].ch>>str[i].b;
            str[i].a++;str[i].b++;
            //printf("%d    b=%d\n",a,b);
            int fa=Find(str[i].a),fb=Find(str[i].b);
            //printf("a=%d,b=%d,fa=%d,fb=%d\n",a,b,fa,fb);
            if(str[i].ch=='=')
                f[fa]=fb;
        }
        for(int i=1;i<=m;i++)
        {
            if(str[i].ch=='=')
                continue;
            if(str[i].ch=='<')
            {
               int fa=Find(str[i].a),fb=Find(str[i].b);
               in[fa]++;
               v[fb].push_back(fa);
            }
            else if(str[i].ch=='>')
            {
                int fa=Find(str[i].a),fb=Find(str[i].b);
               in[fb]++;
               v[fa].push_back(fb);
            }
        }
        tp();
        cout<<ans[flag]<<endl;
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章