zoukankan      html  css  js  c++  java
  • 2015 Multi-University Training Contest 2 1006 Friends 壮压

    题目链接

    题意:t 组測试数据,每组測试数据有 n个人,m条关系

    每条关系能够是 “线上关系” 或者 “线下关系”。 要求每一个人的线上关系(条数) == 线下关系(条数)

    问共同拥有几种分配方法

    思路:

    ①由于要使每一个人的线上关系的总数 == 线下关系 的总数。那么总关系数一定是偶数所以当m为奇数时,方法数肯定为0;

    ②由于每条边仅仅有两种状态。online 或 offline,所以能够用壮压来做,1表示online, 0表示offline;

    ③m最大有 (8*(8-1))/2 = 28条,1<<28 非常大,要TLE,所以用中途相遇法来做 

    ④将每种状态每一个点的 online 和offline个数到 p[N] 里(p[N]用pair定义)然后前半部分倒置存入map数组就能够了

    代码例如以下:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<iostream>
    #include<algorithm>
    #include<map>
    using namespace std;
    
    typedef long long ll;
    typedef pair<ll, ll>pii; 
    const int N = 1e5+10;
    const int INF = 1e9+7;
    int n, m;
    int x[100], y[100];
    int s[100], e[100];
    int on[10], off[10];
    map<pii, int>mp;
    pii p[1 << 14];
    
    void work()
    {
    	for(int i = 0; i < (1 << (m/2)); i++)
    	{
    		memset(on, 0,sizeof(on));
    		memset(off, 0, sizeof(off));
    		for(int j = 0; j < (m/2); j++)
    		{
    			if(i & (1 << j))
    			{
    				on[s[j]]++, on[e[j]]++;
    			}
    			else
    			{
    				off[s[j]]++, off[e[j]]++;
    			}
    		}
    		for(int k = 0; k < n; k++)
    		{
    			int cnt = min(on[k], off[k]);
    			on[k] -= cnt, off[k] -= cnt;
    		}
    		p[i] = {0,0};
    		for(int k = 0; k < n; k++) 
    		{
    			p[i].first = p[i].first * 100 + on[k];
    			p[i].second = p[i].second * 100 + off[k];
    		}
    	}
    }
    
    int main()
    {
    	int t;
    	scanf("%d", &t);
    	while(t--)
    	{
    		scanf("%d%d", &n, &m);
    		for(int i = 0; i < m; i++)
    		{
    			scanf("%d%d", &x[i], &y[i]);
    			x[i]--, y[i]--;
    		}
    		if(m % 2) 
    		{
    			printf("0
    "); continue;
    		}
    		for(int i = 0; i < (m/2); i++)
    		{
    			s[i] = x[i], e[i] = y[i];
    		}
    		work();
    		mp.clear();
    		for(int i = 0; i < (1 << (m/2)); i++)
    		{
    			mp[{p[i].second, p[i].first}]++;
    		}
    		for(int i = m/2; i < m; i++)
    		{
    			s[i-m/2] = x[i], e[i-m/2] = y[i];
    		}
    		work();
    		ll ans = 0;
    		for(int i = 0; i < (1 << (m/2)); i++)
    		{
    			if(mp.count(p[i]))
    			{
    				ans += mp[p[i]];
    			}
    		}
    		printf("%I64d
    ", ans);
    	}
    	return 0;
    } 




  • 相关阅读:
    LIS
    原根
    数三角形
    组合数问题
    最短路问题
    2020总结
    树状数组
    康托展开
    LCA
    并查集
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/7096397.html
Copyright © 2011-2022 走看看