1.旅行商问题
核心思路
用二进制表示一个集合S,如101101 表{0,2,3,5},即第i位为1则i在集合中。
判断j集合S 第v位 是不是1: (S >> v)&1 == 1 则是1
= bit(1111..n...1)。
在S集合的第i位插入 S I (1 << i)或 S + (1 << i)。
表示i集合,最后停留在j点。
u表示出发点,v表要到达的点,则
AC代码
#include<bits/stdc++.h>
using namespace std;
int dp[100010][110];
int w[100][100];
int n;
int main(){
cin>>n;
for(int i = 0;i < n*(n+1);i++){
int u,v;
cin>>u>>v;
cin>>w[u][v];
}
for(int i = 0;i <= 100000;i++){
for(int j = 0;j <= 99;j++){
dp[i][j] = 1e9;
}
}
dp[1][0] = 0;
int ALL = (1 <<(n+1))-1;
for(int S = 1;S < ALL;S++){
for(int u = 0;u <= n;u++){
for(int v = 1;v <= n;v++){
if(((S >> v) & 1) == 0){
dp[S|(1 << v)][v] = min(dp[S+(1 << v)][v],dp[S][u]+w[u][v]);
}
}
}
}
int ret = 1e9;
for(int u = 1;u <= n;u++){
ret = min(ret,dp[ALL][u]+w[u][0]);
}
cout<<ret;
return 0;
}
B. 例题 2 Cows in a Skyscraper
题目描述
A little known fact about Bessie and friends is that they love stair climbing races. A better known fact is that cows really don't like going down stairs. So after the cows finish racing to the top of their favorite skyscraper, they had a problem. Refusing to climb back down using the stairs, the cows are forced to use the elevator in order to get back to the ground floor.
The elevator has a maximum weight capacity of W (1 <= W <= 100,000,000) pounds and cow i weighs C_i (1 <= C_i <= W) pounds. Please help Bessie figure out how to get all the N (1 <= N <= 18) of the cows to the ground floor using the least number of elevator rides. The sum of the weights of the cows on each elevator ride must be no larger than W.
给出n个物品,体积为w[i],现把其分成若干组,要求每组总体积<=W,问最小分组。(n<=18)
输入格式
* Line 1: N and W separated by a space.
* Lines 2..1+N: Line i+1 contains the integer C_i, giving the weight of one of the cows.
输出格式
* A single integer, R, indicating the minimum number of elevator rides needed.
one of the R trips down the elevator.
输入输出样例
输入 #1复制
4 10 5 6 3 7
输出 #1复制
3
说明/提示
There are four cows weighing 5, 6, 3, and 7 pounds. The elevator has a maximum weight capacity of 10 pounds.
We can put the cow weighing 3 on the same elevator as any other cow but the other three cows are too heavy to be combined. For the solution above, elevator ride 1 involves cow #1 and #3, elevator ride 2 involves cow #2, and elevator ride 3 involves cow #4. Several other solutions are possible for this input.
核心思路
s'为S的子集。
如何判断是不是 S | S' == S 则是。
原因:多出来到就不是了。
优化:从集合S开始,倒序枚举 用 T &= S强行枚举。
时间复杂度:
AC代码
#include<bits/stdc++.h>
using namespace std;
int dp[1000010],sum[1000010],c[100010];
int w;
int n;
int main(){
cin>>n>>w;;
for(int i = 0;i <= 1000000;i++){
dp[i] = 1e9;
}
for(int i = 0;i < n;i++){
cin>>c[i];
}
int ALL = (1 << n)-1;
for(int S = 1;S <= ALL;S++){
for(int i = 0;i < n;i++){
if((S >> i)& 1) sum[S] += c[i];
}
}
dp[0] = 0;
for(int S = 1;S <= ALL;S++){
for(int T = S;T >= 1;T--){
T &= S;
if( sum[T] <= w){
dp[S] = min(dp[S],dp[S-T]+1);
}
}
}
cout<<dp[ALL];
return 0;
}
C. 例题 Corn Fields
题目描述
Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can't be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.
Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.
农场主 JohnJohn 新买了一块长方形的新牧场,这块牧场被划分成 �M 行 �N 列 (1≤�≤12;1≤�≤12)(1≤M≤12;1≤N≤12),每一格都是一块正方形的土地。 JohnJohn 打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是 JohnJohn 不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
JohnJohn 想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
输入格式
第一行:两个整数 �M 和 �N,用空格隔开。
第 22 到第 �+1M+1 行:每行包含 �N 个用空格隔开的整数,描述了每块土地的状态。第 �+1i+1 行描述了第 �i 行的土地,所有整数均为 00 或 11 ,是 11 的话,表示这块土地足够肥沃,00 则表示这块土地不适合种草。
输出格式
一个整数,即牧场分配总方案数除以 100,000,000100,000,000 的余数。
输入输出样例
输入 #1复制
2 3 1 1 1 0 1 0
输出 #1复制
9
AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 12+5,maxs = (1 << 12)+5;
int n,m;
int a[maxn][maxn];
int dp[maxn][maxs];
bool check(int i ,int S){
int last = 100;
for(int j = 0;j < m;j++){
if((S >> j)& 1){
if(a[i][j+1] == 0)return 0;
if(j == last+1)return 0;
last = j;
}
}
return 1;
}
const int mod = 1e8;
int main(){
cin>>n>>m;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= m;j++){
cin>>a[i][j];
}
}
int ALL = (1 << m)-1;
dp[0][0] = 1;
for(int i = 0;i < n;i++){
for(int S = 0;S <= ALL;S++){
if(dp[i][S] > 0){
int T = S ^ ALL;
for(int TT = T;TT >= 0;TT--){
TT &= T;
if(check(i+1,TT)) dp[i+1][TT] = (dp[i][S]+dp[i+1][TT])%mod;
}
}
}
}
int ret = 0;
for(int S = 0;S <= ALL;S++)ret = (ret+dp[n][S])%mod;
cout<< ret;
return 0;
}
计算可能的方法类似摆花,可以看我之前的题解。
D. 排列
时间限制:1000 ms内存限制:256 MB类型:传统评测:文本比较上传者: sysulby
题目描述
原题来自:SCOI 2007
给一个数字串 和正整数 ,统计 有多少种不同的排列能被 整除(可以有前导 0)。
例如 123434 有 种排列能被 整除,其中末位为 2 的有 种,末位为 4 的有 种。
输入格式
第一行有一个整数T,表示测试数据的个数。
每组数据一行,有一个字符串 与一个整数 ,保证 中只包含数字字符。
输出格式
每组数据输出一行,一个整数,表示能被 整除的排列的个数。
样例
样例输入复制
7
000 1
001 1
1234567890 1
123434 2
1234 7
12345 17
12345678 29
样例输出复制
1
3
3628800
90
3
6
1398
AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 15+5,maxs = (1 << 10)+5;
string s;
long long d;
long long dp[maxs][1001];
long long cnt[100],fac[100];
int main(){
int T;
cin>>T;
while(T--){
cin>>s>>d;
int n = s.size();
int ALL = (1 << n)-1;
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i = 0;i <= 9;i++)cnt[i] = 0,fac[i] = 1;
for(int i = 0;i < n;i++){
cnt[s[i]-'0']++;
}
for(int i = 0;i <= 9;i++){
for(int j = 1;j <= cnt[i];j++){
fac[i] *= j;
}
}
for(int S = 0;S < ALL;S++){
for(int r = 0;r < d;r++){
if(dp[S][r]){
for(int i = 0;i < n;i++){
if(((S >> i)&1) == 0){
dp[S+(1 << i)][(r*10+s[i]-'0')%d] += dp[S][r];
}
}
}
}
}
long long ans = dp[ALL][0];
for(int i = 0;i <= 9;i++){
ans = ans/fac[i];
}
cout<<ans<<endl;
}
return 0;
}