思路:
具体实现:
b[i][j]
可与b[i-2][j] 和 b[i-1][j-1] 和 b[i-1][j+1]
共同决定b[i][j]
为四周为偶数,若其他三边一直,则b[i][j]
这最后一边就可以推出来,相等于已知O(2^n)
枚举第一行的所有状态,如此判断是否满足情况代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
#define mkpr make_pair
#define x first
#define y second
//#define int long long
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;
const int N = 30, M = 5;
const int YB = 8, YM = 1e8;
const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int T, cases;
int n, m, times;
int a[N][N], b[N][N];
int check(int s)
{
memset(b, 0, sizeof b);
for (int i = 0; i < n; i ++ )
{
if((s >> i) & 1) b[0][i] = 1;
else if(a[0][i]) return INF;
}
for (int i = 1; i < n; i ++ )
for (int j = 0; j < n; j ++ )
{
int sum = 0;
if(i > 1) sum += b[i - 2][j];
if(j > 0) sum += b[i - 1][j - 1];
if(j < n - 1) sum += b[i - 1][j + 1];
b[i][j] = sum & 1;
if(!b[i][j] && a[i][j]) return INF;
}
int res = 0;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
if(a[i][j] ^ b[i][j]) res ++;
return res;
}
void solve()
{
cin >> n;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
scanf("%d", &a[i][j]);
int res = INF;
for (int i = 0; i < 1 << n; i ++ )
res = min(res, check(i));
printf("Case %d: ", cases);
if(res == INF) printf("-1\n");
else printf("%d\n", res);
return;
}
signed main()
{
//fast;
T = 1;
scanf("%d", &T);
// while(T -- )
for (cases = 1; cases <= T; cases ++ )
solve();
return 0;
}
思路:
s >> i & 1
判断i
位置是否过方块,s | 1 << i
表示在i
位置放上方块,连续|
表示连续放方块代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
#define mkpr make_pair
#define x first
#define y second
//#define int long long
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;
const int N = 30, M = 5;
const int YB = 8, YM = 1e8;
const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int T, cases;
int n, m, times;
int H, W, A, B;
int ans;
void dfs(int s, int bit, int a, int b)
{
if(s == H * W)
{
ans ++;
return;
}
// 此处已经填过了,直接到下一个格子
if( bit >> s & 1) return dfs(s + 1, bit, a, b);
// 先填 1x2 的格子,因为有分支,可以递归到所有更多情况
if(a)
{
// 横着放
if(s % W < W - 1 && !(bit >> s + 1 & 1) ) dfs(s + 1, bit | 1 << s | 1 << s + 1, a - 1, b);
// 竖着放
if(s + W < H * W) dfs(s + 1, bit | 1 << s | 1 << s + W, a - 1, b);
}
// 填 1x1 的格子
if(b) return dfs(s + 1, bit | 1 << s, a, b - 1);
return;
}
void solve()
{
cin >> H >> W >> A >> B;
dfs(0, 0, A, B);
cout << ans << endl;
return;
}
signed main()
{
T = 1;
//fast;cin >> T;
//scanf("%d", &T);
//for (cases = 1; cases <= T; cases ++ )
while(T -- )
solve();
return 0;
}
思路:
代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
#define mkpr make_pair
#define x first
#define y second
#define int long long
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int mod = 1e9;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;
const int N = 13, M = 5;
const int YB = 8, YM = 1e8;
const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int T, cases;
int n, m, times;
int row[N], st[1 << N];
int f[1 << N][1 << N];
void solve()
{
cin >> n >> m;
// 输入每一行的二进制表示状态
for (int i = 1; i <= n; i ++ )
for (int j = 0; j < m; j ++ )
{
int x;
cin >> x;
row[i] |= x << j;
}
// 预处理不含相邻 1 的状态
int idx = 0;
for (int i = 0; i < 1 << m; i ++ )
if( !(i & i << 1) )
st[idx ++ ] = i;
// 预处理满足第一行的状态
for (int i = 0; i < idx; i ++ )
if( (row[1] & st[i]) == st[i])
f[1][i] = 1;
// 递推计算其他行的状态
for (int i = 2; i <= n; i ++ )
for (int j = 0; j < idx; j ++ )
if( (row[i] & st[j]) == st[j])
for (int k = 0; k < idx; k ++ )
if( !(st[j] & st[k]) )
f[i][j] = (f[i][j] + f[i - 1][k]) % mod;
// 计算第 n 行的合理方案
int res = 0;
for (int i = 0; i < idx; i ++ )
res = (res + f[n][i]) % mod;
cout << res << endl;
return;
}
signed main()
{
T = 1;
//fast;cin >> T;
//scanf("%d", &T);
//for (cases = 1; cases <= T; cases ++ )
while(T -- )
solve();
return 0;
}
思路:
具体实现:
和 mod 200
的两组数据2^8-1 = 255, 255 > 200
所以我们至多只需枚举前8位数的所有方案即可枚举出答案总结一下:
代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
#define mkpr make_pair
#define x first
#define y second
#define int long long
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int mod = 200;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;
const int N = 210, M = 5;
const int YB = 8, YM = 1e8;
const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int T, cases;
int n, m, times;
int a[N];
vector<vector<int>> g[N];
void print(int x)
{
int t1 = g[x][0].size(), t2 = g[x][1].size();
cout << t1 << " ";
for (int i = 0; i < t1; i ++ )
cout << g[x][0][i] << " ";
cout << endl;
cout << t2 << " ";
for (int i = 0; i < t2; i ++ )
cout << g[x][1][i] << " ";
cout << endl;
return;
}
void solve()
{
cin >> n;
for (int i = 0; i < n; i ++ )
cin >> a[i];
// 至多枚举前八个a[i]的所有状态
for (int i = 1; i < 1 << min((int)8, n); i ++ )
{
int s = 0;
vector<int> temp;
for (int j = 0; j < 8; j ++ )
if(i >> j & 1)
{
s = (s + a[j]) % mod;
temp.push_back(j + 1);
}
g[s].push_back(temp);
}
// 枚举检查即可
for (int i = 0; i < 200; i ++ )
if(g[i].size() >= 2)
{
cout << "YES" << endl;
print(i);
return;
}
cout << "NO" << endl;
return;
}
signed main()
{
T = 1;
//fast;cin >> T;
//scanf("%d", &T);
//for (cases = 1; cases <= T; cases ++ )
while(T -- )
solve();
return 0;
}
思路:
具体实现:
代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fast ios::sync_with_stdio(false), cin.tie(nullptr); cout.tie(nullptr)
#define mkpr make_pair
#define x first
#define y second
#define int long long
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;
const int N = 15, M = N * 2;
const int YB = 8, YM = 1e8;
const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
int T, cases;
int n, m, times;
int f[1 << N][N]; // 经过的点为 i ,且当前点为 j 的路径的最小值
int g[N][N];
void floyd()
{
for (int k = 0; k < n; k ++ )
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
void solve()
{
memset(g, 0x3f, sizeof g);
n ++;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
cin >> g[i][j];
floyd();
memset(f, 0x3f, sizeof f);
f[1][0] = 0;
// 最短 Hamilton 回路
for (int i = 0; i < 1 << n; i ++ )
for (int j = 0; j < n; j ++ )
if(i >> j & 1)
for (int k = 0; k < n; k ++ )
if(i - (1 << j) >> k & 1)
f[i][j] = min(f[i][j], f[i - (1 << j)][k] + g[k][j]);
// floyd 回到起点 0
int res = INF;
for (int i = 1; i < n; i ++ )
res = min(res, f[(1 << n) - 1][i] + g[i][0]);
cout << res << endl;
return;
}
signed main()
{
T = 1;
//fast;cin >> T;
//scanf("%d", &T);
//for (cases = 1; cases <= T; cases ++ )
while(cin >> n, n)
solve();
return 0;
}
思路:
代码如下:
#include
#include
#include
using namespace std;
const int N = 1e7 + 10, mod = 1e9 + 7;
int n, m;
// 0 0
// 0 0
// 集合:所有 第 i - 1 列已经装满,开始装第 i 层,且第 i 列的状态为 j 的方案
// 属性:数量
int f[2][4]; // 滚动数组
int g[4][4] = {
{1, 1, 1, 1},
{0, 0, 1, 1},
{0, 1, 0, 1},
{1, 0, 0, 0},
};
int main()
{
cin >> n;
f[1][0] = 1;
for (int i = 1; i <= n; i ++ )
{
memset(f[i + 1 & 1], 0, sizeof f[0]);
for (int j = 0; j < 4; j ++ )
for (int k = 0; k < 4; k ++ )
if(g[j][k])
f[i + 1 & 1][k] = (f[i + 1 & 1][k] + f[i & 1][j]) % mod;
}
cout << f[n + 1 & 1][0] << endl;
return 0;
}