zoukankan      html  css  js  c++  java
  • 2019-2020 ICPC Asia Taipei-Hsinchu Regional Contest I——The Spectrum dfs+剪枝

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <cmath>
    using namespace std;
    const int N = 2e3;
    int n, arr[N + 5], cnt[N + 5], maxv;
    vector<vector<int>> res;
    vector<int> ans;
    //现在多少数
    //最大是多少
    void solve(int u, int maxnow)
    {
    	if (u == n)
    	{
    		res.push_back(ans);
    		sort(res.back().begin(), res.back().end());
    		return;
    	}
    	//最大数 只能构建一次 如果是0了 那么就往前找最大的
    	while (cnt[maxnow] == 0)
    		--maxnow;
    	//如果最大的次数 是 >2
    	//那么这个方案就一定不合法
    	if (cnt[maxnow] > 2)
    		return;
    	//如果为0 就说明是 maxnow -0
    	//				   maxnow+k  -  (k+0)
    	//同时加2 个
    	if (cnt[maxnow] == 2)
    	{
    		bool ok = true;
    		ans.push_back(maxnow);
    		//构建k
    		ans.push_back(maxv - maxnow);
    		//当加入这两个数字之后
    		//判断是否 是否还能构成原来的序列
    		//也就是 check 有没有出现 没有出现过的差
    		//同时也把能出现差的次数减去
    		//那么最后构建的时候 最大的差就只是1 或者 2
    		for(int i = 0; i < u; ++ i)
    			if (-- cnt[abs(ans[i] - ans[u])] < 0)
    				ok = false;
    		for(int i = 0; i < u + 1; ++ i)
    			if (-- cnt[abs(ans[i] - ans[u + 1])] < 0)
    				ok = false;
    		//如果没有出现过的话  那么就是可以继续往下找
    		if(ok)
    			solve(u + 2, maxnow);
    		//不能 就 恢复现场
    		for(int i = 0; i < u; ++ i)
    			++ cnt[abs(ans[i] - ans[u])];
    		for(int i = 0; i < u + 1; ++ i)
    			++ cnt[abs(ans[i] - ans[u + 1])];
    		ans.pop_back();
    		ans.pop_back();
    		return;
    	}
    	//只出现一次
    	//就  只加入一个数字
    	//分别check
    	ans.push_back(maxnow);
    	bool ok = true;
    	for(int i = 0; i < u; ++ i)
    		if (-- cnt[abs(ans[i] - ans[u])] < 0)
    			ok = false;
    	if(ok)
    		solve(u + 1, maxnow);
    	for(int i = 0; i < u; ++i)
    		++ cnt[abs(ans[i] - ans[u])];
    	ans.pop_back();
    
    	ok = true;
    	ans.push_back(maxv - maxnow);
    	for(int i = 0; i < u; ++ i)
    		if (-- cnt[abs(ans[i] - ans[u])] < 0)
    			ok = false;
    	if(ok)
    		solve(u + 1, maxnow);
    	for(int i = 0; i < u; ++i)
    		++ cnt[abs(ans[i] - ans[u])];
    	ans.pop_back();
    }
    
    int main()
    {
    	cin >> n;
    	for (int i = 1; i <= n * (n - 1) / 2; ++i)
    	{
    		cin >> arr[i];
    		if (arr[i] >= 1000)
    		{
    			cout << 0 << endl;
    			return 0;
    		}
    		cnt[arr[i]] += 1;
    		//出现的最大数
    		maxv = max(maxv, arr[i]);
    	}
    	//如果最大数出现了两次,那么就肯定有负数
    	if (cnt[maxv] > 1)
    	{
    		cout << 0 << endl;
    		return 0;
    	}
    	//x1 为0
    	//那么最大就只能是maxv
    	ans.push_back(0);
    	ans.push_back(maxv);
    	cnt[maxv] = 0;
    	solve(2, maxv);
    	sort(res.begin(), res.end());
    	int sum = res.size();
    	printf("%d
    ", sum);
    	for (int i = 0; i < sum; ++ i)
    	{
    		for (int j = 0; j < n; ++ j)
    			cout<<res[i][j]<<" ";
    		cout << endl;
    	}
    	return 0;
    }
    

    但是,还有一个很重要的细节(虽说好像不写也能过)。

    就是这个数正好是最大值的1/2,这种情况的话我们就按照他只出现一次处理就好了。举个例子:原数列为 0 1 2 3 4。即输入为

    5

    1 1 1 1 2 2 2 3 3 4

    时,枚举到2的时候会发现4-2=2,这时候虽然2的差值为2,但是我们应当按照差值为1讨论。(具体看代码)

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <map>
    #include <cmath>
    using namespace std;
    const int N = 2e3;
    int n, arr[N + 5], cnt[N + 5], maxv;
    vector<vector<int>> res;
    vector<int> ans;
    //现在多少数
    //最大是多少
    void solve(int u, int maxnow)
    {
    	if (u == n)
    	{
    		res.push_back(ans);
    		sort(res.back().begin(), res.back().end());
    		return;
    	}
    	//最大数 只能构建一次 如果是0了 那么就往前找最大的
    	while (cnt[maxnow] == 0)
    		--maxnow;
    	//如果最大的次数 是 >2
    	//那么这个方案就一定不合法
    	if (cnt[maxnow] > 2)
    		return;
    	if(cnt[maxnow] == 1 || ( cnt[maxnow] == 2 && maxv==2*maxnow ))
    	{
    		//只出现一次
    		//就  只加入一个数字
    		//分别check
    		ans.push_back(maxnow);
    		bool ok = true;
    		for(int i = 0; i < u; ++ i)
    			if (-- cnt[abs(ans[i] - ans[u])] < 0)
    				ok = false;
    		if(ok)
    			solve(u + 1, maxnow);
    		for(int i = 0; i < u; ++i)
    			++ cnt[abs(ans[i] - ans[u])];
    		ans.pop_back();
    
    		ok = true;
    		ans.push_back(maxv - maxnow);
    		for(int i = 0; i < u; ++ i)
    			if (-- cnt[abs(ans[i] - ans[u])] < 0)
    				ok = false;
    		if(ok)
    			solve(u + 1, maxnow);
    		for(int i = 0; i < u; ++i)
    			++ cnt[abs(ans[i] - ans[u])];
    		ans.pop_back();
    	}
    	//如果为0 就说明是 maxnow -0
    	//				   maxnow+k  -  (k+0)
    	//同时加2 个
    	else
    	{
    		bool ok = true;
    		ans.push_back(maxnow);
    		//构建k
    		ans.push_back(maxv - maxnow);
    		//当加入这两个数字之后
    		//判断是否 是否还能构成原来的序列
    		//也就是 check 有没有出现 没有出现过的差
    		//同时也把能出现差的次数减去
    		//那么最后构建的时候 最大的差就只是1 或者 2
    		for(int i = 0; i < u; ++ i)
    			if (-- cnt[abs(ans[i] - ans[u])] < 0)
    				ok = false;
    		for(int i = 0; i < u + 1; ++ i)
    			if (-- cnt[abs(ans[i] - ans[u + 1])] < 0)
    				ok = false;
    		//如果没有出现过的话  那么就是可以继续往下找
    		if(ok)
    			solve(u + 2, maxnow);
    		//不能 就 恢复现场
    		for(int i = 0; i < u; ++ i)
    			++ cnt[abs(ans[i] - ans[u])];
    		for(int i = 0; i < u + 1; ++ i)
    			++ cnt[abs(ans[i] - ans[u + 1])];
    		ans.pop_back();
    		ans.pop_back();
    		return;
    	}
    }
    
    int main()
    {
    	cin >> n;
    	for (int i = 1; i <= n * (n - 1) / 2; ++i)
    	{
    		cin >> arr[i];
    		if (arr[i] >= 1000)
    		{
    			cout << 0 << endl;
    			return 0;
    		}
    		cnt[arr[i]] += 1;
    		//出现的最大数
    		maxv = max(maxv, arr[i]);
    	}
    	//如果最大数出现了两次,那么就肯定有负数
    	if (cnt[maxv] > 1)
    	{
    		cout << 0 << endl;
    		return 0;
    	}
    	//x1 为0
    	//那么最大就只能是maxv
    	ans.push_back(0);
    	ans.push_back(maxv);
    	cnt[maxv] = 0;
    	solve(2, maxv);
    	sort(res.begin(), res.end());
    	map<vector<int>,bool>mp;
    	int sum = 0;
    	for(int i = 0; i < res.size(); i ++)
    	{
    		if(mp[res[i]] == 0)
    		{
    			mp[res[i]] == 1;
    			sum ++ ;
    		}
    	}
    	cout << sum << endl;
    	mp.clear();
    	for (int i = 0; i < sum; ++ i)
    	{
    		if(mp[res[i]]==0)
    		{
    			for (int j = 0; j < n; ++ j)
    				cout<<res[i][j]<<" ";
    			cout << endl;
    			mp[res[i]]=1;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    WebSocket 实战--转
    ELK原理与介绍
    linux命令:使用less从后向前查看日志信息
    Unity创作赛车游戏的四款插件
    Dolly
    shot
    Unity3D获取Android平台的电量
    Unity制作王者荣耀商业级手游
    unity热更新AssetBundle框架设计_框架篇
    喷气传动
  • 原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12742452.html
Copyright © 2011-2022 走看看