Topoi 测验1301, 问题C: 1959: 解题 解题报告
Topoi(一个经常会炸的网站)

很久以前的题目了, 刚开了博客,来写一波题解
先看一波提交记录:


调了好几天QAQ
唉! 要是这些高手里有我估计直接 输出1 就AC了
算法
DFS + 优化剪枝(用了一点状态压缩)
剪枝
1:求最小值很容易向导最优化剪枝
if(ws>=ans) return; //剪枝 1:最优化剪枝
2:若一个高手会做的题有另一个高手都会做,则这个高手没有用
for(int i=1;i<=w;i++)
for(int j=1;j<i;j++)
{;
if((a[i].sn|a[j].sn)==a[j].sn) {kk[i]=1; break;} //kk表示这个高手有没有用
//剪枝 2:若这个高手会做的题有另一个人全会做,则是废物,去掉没有用的高手 (核心剪枝)
}
3:若有一个题只有一个高手能做,则将这个高手“特招”
for(int i=1;i<=w;i++)
for(int j=1;j<i;j++)
{;
if((a[i].sn|a[j].sn)==a[j].sn) {kk[i]=1; break;} //kk表示这个高手有没有用
//剪枝 2:若这个高手会做的题有另一个人全会做,则是废物,去掉没有用的高手 (核心剪枝)
}
顺序性优化:将做题多的高手排在前面(也许没用)
bool cmp(node x,node y){return x.sum>y.sum;}
sort(a+1,a+n+1,cmp); //顺序性优化: 按会做的题数排序
加上这些优化在top上大概200多ms(第二次AC记录),应该还有其他优化,但因为太ruo想不出来
这题用二进制表示状态好像多此一举
最后,附上完整代码(有点小长)
打注释都打了半个多小时QAQ
代码
#include <bits/stdc++.h>
using namespace std;
int n,w,ans=1e9,tt;//tt记录特招人数
bool k[66],kk[66],vis[66]; //k记录是否“特招”,kk记录有木有用,vis标记访问
struct node{
long long sn,sum;
int p[66];
}a[66]; //p数组记录每个高手能做的题,sn记录状态,sum记录题数,
long long num[66],q[66][66],s[66],ss[66];
//q记录每个题能做的高手,s和ss记录每个题能做的人数(有点重复了),num记录每个题的二进制,
bool cmp(node x,node y){return x.sum>y.sum;}
void find(int x,int ws,long long ssum) //x表示当前题号, ws表示高手数, ssum用二进制存储状态
{
if(ws>=ans) return; //剪枝 1:最优化剪枝
if(x>n) {ans=ws; return;} //结束条件, 更新答案
if(((ssum>>(x-1))&1==1)) {find(x+1,ws,ssum); return;} //如果这题已做,往后搜索
for(int i=1;i<=s[x];i++)
{
if(k[q[x][i]]) continue; //判断这个高手是不是 “特招”的
int tmp=q[x][i];
if(vis[tmp]) continue; //如果这个高手已经用过了
vis[tmp]=1;
find(x+1,ws+1,ssum|a[tmp].sn); //一定要用 | 运算,防止重复
vis[tmp]=0;
}
return;
}
int main()
{
scanf("%d%d",&n,&w);
num[1]=1;
for(int i=2;i<=n;i++) num[i]=num[i-1]<<1; //用2进制来表示状态
for(int i=1;i<=w;i++)
{
int x;
scanf("%d",&x);
for(int j=1;j<=x;j++)
{
int y;
scanf("%d",&y);
s[y]++;
if((a[i].sn|num[y])!=a[i].sn) //注意这里要用 | 运算,判断这题有没有出现过
a[i].sum++,a[i].p[a[i].sum]=y; //存储每个高手能做的题
a[i].sn=a[i].sn|num[y]; //更新状态
}
}
sort(a+1,a+n+1,cmp); //顺序性优化: 按会做的题数排序
for(int i=1;i<=w;i++)
for(int j=1;j<i;j++)
{
// if(i==j||kk[j]) continue;
if((a[i].sn|a[j].sn)==a[j].sn) {kk[i]=1; break;} //kk表示这个高手有没有用
//剪枝 2:若这个高手会做的题有另一个人全会做,则是废物,去掉没有用的高手 (核心剪枝)
}
long long ttmp=0;
for(int i=1;i<=w;i++)
{
if(kk[i]) continue; //直接过滤废物高手
for(int j=1;j<=a[i].sum;j++)
{
int tmp=a[i].p[j];
q[tmp][++ss[tmp]]=i;
}
}
//记录能做每个题的高手
for(int i=1;i<=n;i++)
{
if(s[i]==1&&!k[q[i][1]]) //判断第i题是不是只有一个高手会做
{
tt++;
//printf("%d\n",q[i][1]);
int tmp=q[i][1];
ttmp=ttmp|a[tmp].sn; //ttmp记录初始的搜索状态
k[tmp]=1; //标记这个高手不用考虑
}
} //剪枝 3:若有一个题只有一个高手会做,将他“特招”进来 (这个剪枝收益蛮大的)
find(1,0,ttmp);
printf("%d",ans+tt); //注意不要忘了加上“特招”人数
return 0;
}
Topoi 测验1301, 问题C: 1959: 解题 解题报告的更多相关文章
- TOPOI 测验1320, 问题C: 4410: [CF41D]Pawn 解题报告
题目链接 题目大意 在一个树阵中按一定走法取一些树,使和最大且被 k+1整除 解题思路 类似一个数塔问题 因为最后的结果要被 k+1 整除,所以可以记录到每一个点 对 k+1 取余结果不同的最优解( ...
- 洛谷 P4397 [JLOI2014]聪明的燕姿 / TOPOI 测验1315, 问题E: 1935: 聪明的燕姿 解题报告
题目链接 : 1. 洛谷 2.topoi . 大致题意:输入一个数s,找出所有约数和为s的数 关于一个数的约数和求法: 一个>1的整数可以被分解为多个 质数 的乘方,设数 s = p1k1 * ...
- HDU 3791二叉搜索树解题(解题报告)
1.题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3791 2.参考解题 http://blog.csdn.net/u013447865/articl ...
- 怎样解题 --解题表(how to solve it)
<怎样解题> 美.波利亚 下面是来自书中的解题表: 理解题目 第一 理解题目 你必须理解题目 未知量是什么?已知数据是什么?条件是什么? 条件有可能满足吗?条件是否可以确定未适量?或者它不 ...
- CodeForces 701C They Are Everywhere (滑动窗口)
题目链接:http://codeforces.com/problemset/problem/701/C 题意:找到字符串中能包含所有元素的最短字符串长度. 利用“滑动窗口”解题 解题思路: 1. 遍历 ...
- 【一天一道LeetCode】#63. Unique Paths II
一天一道LeetCode (一)题目 Follow up for "Unique Paths": Now consider if some obstacles are added ...
- 【一天一道LeetCode】#27. Remove Element
一天一道LeetCode系列 (一)题目 Given an array and a value, remove all instances of that value in place and ret ...
- 【一天一道LeetCode】#26. Remove Duplicates from Sorted Array
一天一道LeetCode系列 (一)题目 Given a sorted array, remove the duplicates in place such that each element app ...
- LeetCode7-ReverseInteger
LeetCode7-ReverseInteger LeetCodeeasyOverflow 题目 题目所在链接为 LeetCode-7:ReverseInteger 题目描述 给出一个32位的有符号整 ...
随机推荐
- ORACLE 强制索引
在一些场景下,可能ORACLE不会自动走索引,这时候,如果对业务清晰,可以尝试使用强制索引. 使用强制索引,在SELECT 后面加上/*.......*/ 中间加上索引的属性,代码如下: SELECT ...
- NYOJ-小猴子下落
描述 有一颗二叉树,最大深度为D,且所有叶子的深度都相同.所有结点从左到右从上到下的编号为1,2,3,·····,2的D次方减1.在结点1处放一个小猴子,它会往下跑.每个内结点上都有一个开关,初始全部 ...
- Java集合操作类Collections的一些常用方法
public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); ...
- 在屏幕中间显示,按ESC键后改变字符的颜色
程序功能:编写程序在屏幕中间显示“a”~“z”,并可以让人看清,这个任务比较好实现. (1)在b800:[ 160*12+40*2]处存入a的ASCII码.(2)在循环中使用一个10000000000 ...
- 51nod 1250 排列与交换——dp
题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1250 仔细思考dp. 第一问,考虑已知 i-1 个数有多少种方案. ...
- [.net] 无法创建虚拟目录。已将URL“XXX”映射到IIS Express网站上的一个不同的文件夹
工作时,在修改项目属性,Web中服务器时,出现了下面的错误: 各种折腾后,找到下面的解决方法: 1.找到项目在本地的目录,目录下有当前项目的项目文件,文件名以.csproj为后缀名. 2.用文本编辑软 ...
- zabbix 系列 (1)安装
安装server http://blog.csdn.net/xiegh2014/article/details/54988548 安装 agent http://m.blog.csdn.net/wu2 ...
- js中object、字符串与正则表达式的方法
对象 1.object.hasOwnProperty(name) 检测object是否包含一个名为name的属性,那么hasOwnProperty方法返回true,但是不包括其原型上的属性. 正则表达 ...
- adroid 分辨率适配
(1)drawable-hdpi里面存放高分辨率的图片,如WVGA (480x800),FWVGA (480x854) (2)drawable-mdpi里面存放中等分辨率的图片,如HVGA (320x ...
- OpenCV 鼠标手动绘制掩码图像
OpenCV 鼠标手动绘制掩码图像 完整的代码: #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui ...