A Plug for UNIX

传送门

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PLL;
typedef pair<int, int>PII;
typedef pair<double, double>PDD;
#define I_int ll
inline ll read()
{
    ll x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
#define read read()
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
ll ksm(ll a, ll b, ll p)
{
    ll res = 1;
    while(b)
    {
        if(b & 1)res = res * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return res;
}
const int inf = 0x3f3f3f3f;
#define PI acos(-1)
const int maxn=100000 + 5;///总点个数,随题意改

const int MAX=1<<26;///最大值,随题意改

///链式前向星存储边
///表示u->v 边权为c(容量) 下一条边
struct Edge{
    ll u,v,c,ne;
};

///求最大流
struct Dinic{
    int n,m;///点数,边数
    int edn;///建图时所用边数
    int p[maxn];///链式前向星存图的父节点
    int d[maxn];///分层建图时表示的层数
    int sp,tp;///原点 汇点
    Edge edge[maxn*6];///存储边

    ///初始化
    void init(){
        ///this->sp=sp;//可省去
       /// this->tp=tp;
        edn=0;///清空建图时计边的计数器
         memset(p,-1,sizeof p);
      /// memset(p,-1,sizeof(int)*(n+2));///小优化 仅初始化使用的空间
    }

    void addedge(int u,int v,int c){///建图加边
        edge[edn]={u,v,c,p[u]};p[u]=edn++;///正向一定要加的
        edge[edn]={v,u,0,p[v]};p[v]=edn++;///无向图改成c 反悔边
    }
    ///分层建图并且寻找增广路的过程
    int bfs(){
        queue<int>q;
        while(!q.empty()) q.pop();///清空队列
        memset(d,-1,sizeof d);///初始化距离数组
        d[sp]=0;q.push(sp);///进行分层建图

        while(!q.empty()){
            int cur=q.front();q.pop();
            for(int i=p[cur];~i;i=edge[i].ne){
                int u=edge[i].v;
                if(d[u]==-1&&edge[i].c>0){///容量>0才会有贡献
                    d[u]=d[cur]+1;
                    q.push(u);
                }
            }
        }
        return d[tp]!=-1;///是否存在增广路
    }

    ll dfs(ll a,ll b){
        ll r=0;
        if(a==tp) return b;///到达汇点
        for(int i=p[a];~i&&r<b;i=edge[i].ne){
            int u=edge[i].v;
            if(edge[i].c>0&&d[u]==d[a]+1){
                ///只拓展下一层 并且容量>0才会有贡献
                int x=min(edge[i].c,b-r);///可以增加的流量
                x=dfs(u,x);
                r+=x;///统计流量

                ///更新边权:找到反向边
                ///奇数异或1相当于-1,偶数异或1相当于+1
                edge[i].c-=x;///回溯时更新
                edge[i^1].c+=x;///成对变换
            }
            ///if(!r) break;
        }
       if(!r) d[a]-=2;///uncertain
        return r;
    }

    ll Maxflow(){
        ll total=0,t;
        while(bfs()){
            while(t=dfs(sp,MAX)) total+=t;///增广找到流量
        }
        return total;
    }

}dinic;

map<string,int>s1,s2;///插头和插座
int main()
{
   	int T=read;
   	while(T--){
   		dinic.n=read;
   		dinic.init();
   		s1.clear(),s2.clear();
   		int tot=0,num=0;
   		dinic.sp=80001,dinic.tp=dinic.sp+1;
   		for(int i=1;i<=dinic.n;i++){
            string s;cin>>s;
            s1[s]=++tot;
   		}
   		ll m=read;
   		for(int i=1;i<=m;i++){
            string x,y;cin>>x>>y;
            s2[x]=++num;
            if(s1.find(y)==s1.end()) s1[y]=++tot;
            dinic.addedge(s2[x],m+s1[y],1);
            dinic.addedge(dinic.sp,s2[x],1);
   		}
   		int k=read;
   		for(int i=1;i<=dinic.n;i++){
            dinic.addedge(m+i,m+tot+i,1);
            dinic.addedge(m+tot+i,dinic.tp,1);
   		}
   		for(int i=1;i<=k;i++){
            string x,y;cin>>x>>y;
            dinic.addedge(s1[x]+m,s1[y]+m,inf);
   		}
   		printf("%lld\n",m-dinic.Maxflow());
   		if(T) puts("");
   	}
    return 0;
}


posted @ 2021-05-27 20:28  OvO1  阅读(39)  评论(0编辑  收藏  举报