1013 Battle Over Cities
原来的图不一定连通,所以dfs统计连通块的时候要遍历所有的点。
pta总是有一些奇怪的边缘数据,
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 1000+10;
vector<int> G[maxn];
int n, m, k;
int del[maxn];
bool vis[maxn];
int ans[maxn];
int no;
void dfs(int u, int p){
vis[u] = true;
for(int i=0; i<G[u].size(); i++){
int v = G[u][i];
if(v == p || v==no||vis[v]) continue;
dfs(v, u);
}
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m>>k;
int u, v;
for(int i=1; i<=m; i++){
cin>>u>>v;
G[u].push_back(v), G[v].push_back(u);
}
for(int i=1; i<=k; i++){
cin>>del[i];
int tot = 0;
no = del[i];
cls(vis, 0);
for(int j=1; j<=n; j++){
if(j == del[i]) continue;
if(!vis[j]){
tot++;
dfs(j, -1);
}
}
ans[i] = tot-1;
}
for(int i=1; i<=k; i++) cout<<ans[i]<<endl;
return 0;
}
unidirectional TSP
记录移动状态的dp问题,还算比较的常规
求一条路径最短的矩阵路径,若权重相同则要使行序的字典序最小。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 2000+10;
int num[15][105];
int dp[15][105];
int nex[15][105];
int n, m;
int main(){
ios::sync_with_stdio(false);
while(~scanf("%d%d", &n, &m)){
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
scanf("%d", &num[i][j]);
dp[i][j] = inf;
}
}
int ans = inf;
for(int col=m; col>=1; col--){
for(int row=1; row<=n; row++){
if(col == m) dp[row][col] = num[row][col];
else{
int to[3] = {row-1, row, row+1};
if(row == n) to[2] = 1;
if(row==1) to[0] = n;
sort(to, to+3);
for(int j=0; j<3; j++){
int temp = dp[to[j]][col+1]+num[row][col];
if(temp<dp[row][col]){
dp[row][col] = temp;
nex[row][col] = to[j];
}
}
}
}
}
int mi = inf;
int first = -1;
for(int i=1; i<=n; i++){
if(dp[i][1]<mi){
mi = dp[i][1];
first = i;
}
}
int j=1;
for(int i=first; j<=m; j++){
printf("%d%c", i, j==m?'
':' ');
i = nex[i][j];
}
printf("%d
", mi);
}
return 0;
}
The lightning system
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 1000+10;
struct Node{
int v, k, c, l;
bool operator < (const Node &b) const{
return v<b.v;
}
}node[maxn];
int n;
int dp[maxn];
int pre[maxn];
int main(){
ios::sync_with_stdio(false);
while(cin>>n&&n){
for(int i=1; i<=n; i++){
cin>>node[i].v>>node[i].k>>node[i].c>>node[i].l;
//pre[i] = pre[i-1]+node[i].l;
}
sort(node+1, node+1+n);
pre[0] = 0;
for(int i=1; i<=n; i++) dp[i] = inf, pre[i] = pre[i-1]+node[i].l;
dp[1] = node[1].l*node[1].c+node[1].k;
dp[0] = 0;
for(int i=2; i<=n; i++){
for(int j=0; j<i; j++){
dp[i] = min(dp[i], dp[j]+(pre[i]-pre[j])*node[i].c+node[i].k);
}
}
cout<<dp[n]<<endl;
}
return 0;
}
jin ge jin qu(01背包)
条件有点唬人导致不敢做背包
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 180*50+678+10;
int dp[maxn];
int n;
int a[55];
int remain;
int main(){
ios::sync_with_stdio(false);
int _;
cin>>_;
int kase = 1;
while(_--){
cin>>n>>remain;
int tot = 0;
for(int i=1; i<=n; i++) cin>>a[i], tot+=a[i];
for(int i=1; i<=remain; i++) dp[i] = -1;
dp[0] = 0;
for(int i=1; i<=n; i++){
for(int v=remain-1; v>=a[i]; v--){
if(dp[v-a[i]]>=0){
dp[v] = max(dp[v], dp[v-a[i]]+1);
}
}
}
int mx = -1;
int last = -1;
for(int i=remain-1; i>=0; i--){
if(mx<dp[i]){
mx = dp[i];
last = i;
}
}
cout<<"Case "<<kase++<<": "<<mx+1<<" "<<last+678<<endl;
}
return 0;
}
矩阵的链乘(区间dp)
将问题转化为n-1矩阵的相乘
时间复杂度是(O(n^3))
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 100+10;
int a[maxn];
int dp[maxn][maxn];
int n;
struct Matrix{
int x, y;
}node[maxn];
int main(){
ios::sync_with_stdio(false);
while(cin>>n){
for(int i=1; i<=n; i++) cin>>a[i];
node[1].x=a[1] ,node[1].y=a[2];
for(int i=2; i<=n-1; i++){
node[i].x=a[i], node[i].y=a[i+1];
}
cls(dp, 0x3f);
for(int i=1; i<=n-2; i++){
dp[i][i+1] = node[i].x*node[i].y*node[i+1].y;
}
for(int i=1; i<=n-1; i++) dp[i][i] = 0;
for(int l=3; l<=n-1; l++){
for(int i=1; i<=n-l+1; i++){
int j=i+l-1;
for(int k=i; k<=j; k++){
//cout<<i<<" "<<k<<" "<<j<<endl;
if(dp[i][k]!=inf&&dp[k+1][j]!=inf)
dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]+node[i].x*node[k].y*node[j].y);
}
}
}
//cout<<dp[1][4]<<endl;
cout<<dp[1][n-1]<<endl;
}
return 0;
}
uva 1626 括号完整匹配(区间dp)
这道题的输入正的是蜜汁奇怪, 括号还可以是空串,输入间还要有空行。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 1000+10;
int dp[maxn][maxn];
char s[105];
bool match(char x, char y){
if(x == '(' && y == ')') return true;
if(x == '[' && y == ']') return true;
return false;
}
void print(int l, int r){
if(l>r) return;
if(l == r){
if(s[l]=='('||s[r] == ')') cout<<"()";
else cout<<"[]";
return ;
}
int ans = dp[l][r];
if(match(s[l], s[r])&&ans == dp[l+1][r-1]){
cout<<s[l]; print(l+1, r-1); cout<<s[r];
return ;
}
else{
for(int i=l; i<r; i++){
if(ans ==dp[l][i]+dp[i+1][r]){
print(l, i), print(i+1, r);
break;
}
}
return ;
}
}
int main(){
ios::sync_with_stdio(false);
int _;
scanf("%d", &_);
getchar();
while(_--){
int idx = 0;
gets(s);
while(s[idx] =getchar()){
if(s[idx] == '
') break;
idx++;
}
s[idx] = ' ';
//cout<<s<<'
';
int len = strlen(s);
//cls(dp, 0x3f);
for(int i=0; i<len; i++) {
dp[i][i] = 1;
dp[i+1][i] = 0;
}
for(int i=len-2; i>=0; i--){
for(int j=i+1; j<len; j++){
dp[i][j] = len;
if(match(s[i], s[j])) dp[i][j] = min(dp[i][j], dp[i+1][j-1]);
for(int k=i; k<j; k++){
dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]);
}
}
}
//cout<<dp[0][len-1]<<endl;
print(0, len-1);
cout<<endl;
if(_) cout<<endl;
}
return 0;
}
一个任意的多边形(不一定是凸)剖分的三角形最大面积最小
一个判断是否是凸的+区间dp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 100+10;
struct Node{
int x, y;
}node[maxn];
int n;
double dp[maxn][maxn];
double area(Node a, Node b, Node c){
return 1.0*abs((b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x))/2.0;
}
bool is_convex(int x, int y, int z){
double S = area(node[z], node[x], node[y]);
for(int i=1; i<=n; i++){
if(i == x || i == y || i == z) continue;
double s = area(node[i], node[x], node[y])+area(node[i], node[x], node[z])+area(node[i], node[z], node[y]);
//点在内部,肯定非凸
if(fabs(s-S)<1e-4) return false;
}
return true;
}
int main(){
ios::sync_with_stdio(false);
int _;
cin>>_;
while(_--){
cin>>n;
for(int i=1; i<=n; i++) cin>>node[i].x>>node[i].y;
for(int l=3; l<=n; l++){
for(int i=1; i<=n-l+1; i++){
int j = i+l-1;
if(j>n) continue;
dp[i][j] = 1000000000.0;
for(int k=i+1; k<j; k++){
if(!is_convex(i, k, j)) continue;
//cout<<area(node[i], node[k], node[j])<<endl;
dp[i][j] = min(dp[i][j], max(max(dp[i][k], dp[k][j]), area(node[i], node[k], node[j])));
}
}
}
//cout<<dp[1][n]<<endl;
cout<<fixed<<setprecision(1);
cout<<dp[1][n]<<endl;
}
return 0;
}
uva1025 A spy in the metro
一个人要在T秒的在n站见一个人,使得他在__中途等待的时间最短__, 而不是花费的总时间。
因为终点确定了,所以要倒着dp,不然开始的状态太多了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 2000+10;
int n, t;
bool has_train[55][205][2];
int dp[55][205];
int a[maxn];
int main(){
ios::sync_with_stdio(false);
int kase = 1;
while(cin>>n&&n){
cin>>t;
for(int i=1; i<=n-1; i++) cin>>a[i];
cls(has_train, 0);
int m1;
cin>>m1;
for(int i=1; i<=m1; i++){
int temp;
cin>>temp;
has_train[1][temp][0] = true;
int tot = temp;
for(int j=1; j<n; j++){
tot += a[j];
has_train[j+1][tot][0] = true;
}
}
cin>>m1;
for(int i=1; i<=m1; i++){
int temp;
cin>>temp;
has_train[n][temp][1] = true;
int tot = temp;
for(int j=n-1; j>=1; j--){
tot += a[j];
has_train[j][tot][1] = true;
}
}
cls(dp, 0x3f);
//for(int i=0; i<=t-1; i++) dp[n][i] = inf;
dp[n][t] = 0;
for(int i=t-1; i>=0; i--){
for(int j=1; j<=n; j++){
dp[j][i] = dp[j][i+1]+1;
if(j<n&&has_train[j][i][0]&&i+a[j]<=t){
dp[j][i] = min(dp[j][i], dp[j+1][i+a[j]]);
}
if(j>1&&has_train[j][i][1]&&i+a[j-1]<=t){
dp[j][i] = min(dp[j][i], dp[j-1][i+a[j-1]]);
}
}
}
if(dp[1][0]<inf)
cout<<"Case Number "<<kase++<<": "<<dp[1][0]<<"
";
else cout<<"Case Number "<<kase++<<": impossible
";
}
return 0;
}
/*
3
3
1 2
1 0
1 0
*/
uva 437 巴比伦
每个方块的个数没有限制,将状态进行了相应的映射,使得状态量变小。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 2000+10;
int block[35][3];
int dp[35][35];
int n;
void get(int* v1, int x, int y){
int idx=0;
bool has = false;
for(int i=0; i<3; i++){
if(i == y) continue;
else v1[idx++] = block[x][i];
}
}
int dfs(int u, int v){
int& ans = dp[u][v];
//cout<<u<<" "<<v<<endl;
if(ans>0) return ans;
int v1[2], v2[2];
get(v1, u, v);
for(int i=1; i<=n; i++){
for(int j=0; j<3; j++){
get(v2, i, j);
//cout<<v1[0]<<" "<<v1[1]<<endl;
//cout<<v2[0]<<" "<<v2[1]<<endl;
if(v2[0]<v1[0]&&v2[1]<v1[1]){
ans = max(ans, dfs(i, j));
}
}
}
ans+=block[u][v];
return ans;
}
int main(){
ios::sync_with_stdio(false);
int kase = 1;
while(cin>>n&&n){
for(int i=1; i<=n; i++){
for(int j=0; j<3; j++) cin>>block[i][j];
sort(block[i], block[i]+3);
}
int ans = 0;
cls(dp, 0);
for(int i=1; i<=n; i++){
for(int j=0; j<3; j++){
ans = max(ans, dfs(i, j));
}
}
cout<<"Case "<<kase++<<": maximum height = "<<ans<<endl;
}
return 0;
}
最小汉哈顿距离
又是一个倒着更新的例子。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 1000+10;
double dp[maxn][maxn];
double dist[maxn][maxn];
int x[maxn], y[maxn];
int n;
int main(){
ios::sync_with_stdio(false);
while(cin>>n){
for(int i=1; i<=n; i++) cin>>x[i]>>y[i];
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++) {
dist[i][j] = sqrt(1.0*(x[i]-x[j])*(x[i]-x[j])+1.0*(y[i]-y[j])*(y[i]-y[j]));
}
}
for(int i=n-1; i>=2; i--){
//规定i>j;
for(int j=i-1; j>=1; j--){
if(i == n-1) dp[i][j] = dist[n-1][n]+dist[j][n];
else dp[i][j] = min(dp[i+1][j]+dist[i][i+1], dp[i+1][i]+dist[j][i+1]);
}
}
cout<<fixed<<setprecision(2);
cout<<dp[2][1]+dist[1][2]<<endl;
}
return 0;
}
切割木棒
切割n次,每一次的花费是该木棒的长度
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 50+10;
int dp[maxn][maxn];
int l;
int n;
int a[maxn];
int dfs(int i, int j){
if(i>=j-1) return 0;
int &ans = dp[i][j];
if(ans>0) return ans;
ans = inf;
for(int k=i+1; k<j; k++){
ans = min(ans, dfs(i, k)+dfs(k, j));
}
ans += (a[j]-a[i]);
return ans;
}
int main(){
ios::sync_with_stdio(false);
while(cin>>l&&l){
cin>>n;
cls(dp, 0);
for(int i=1; i<=n; i++) cin>>a[i];
a[0] = 0, a[n+1] = l;
cout<<"The minimum cutting is "<<dfs(0, n+1)<<".
";
}
return 0;
}
树形dp
uva 12186 工人的请愿书
直属的下属在超过T%的人数之后,就会向直属上司进行报告。每一个人最少有(son[u]*T-1)/100+1;
一种向上取整的方法
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 1e5+10;
int n, t;
vector<int> son[maxn];
vector<int> val[maxn];
int dp[maxn];
int dfs(int u){
if(son[u].empty()) return 1;
int &ans = dp[u];
for(int i=0; i<son[u].size(); i++){
int v = son[u][i];
val[u].push_back(dfs(v));
}
//一种算下线的方法。
int mi = (son[u].size()*t-1)/100+1;
sort(val[u].begin(), val[u].end());
for(int i=0; i<mi; i++) ans += val[u][i];
return ans;
}
int main(){
ios::sync_with_stdio(false);
while(cin>>n>>t&&n+t){
for(int i=0; i<=n; i++) son[i].clear(), val[i].clear();
for(int i=0; i<=n; i++) dp[i] = 0;
for(int i=1; i<=n; i++){
int temp;
cin>>temp;
son[temp].push_back(i);
}
cout<<dfs(0)<<endl;
}
return 0;
}
老师教书(状压dp)
ans>=0是已经被访问过的条件
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<sstream>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 1e9;
const int maxn = 120+10;
int c[maxn];
int s, m, n;
int dp[maxn][1<<8][1<<8];
int jiao[maxn];
int dfs(int u, int s0, int s1, int s2){
if(u == n+m+1) return s2==(1<<s)-1?0:inf;
int &ans = dp[u][s1][s2];
//ans>=不是>
if(ans>=0) return ans;
ans = inf;
if(u>m) ans = min(ans, dfs(u+1, s0, s1, s2));
//m0表示即将0->1人教的课。
int m0 = (jiao[u]&s0), m1 = (jiao[u]&s1);
//|是一种教课程的运算, ^是一种减课程的运算
s0 = (s0^m0), s1 = (s1^m1)|(m0), s2 = (s2|m1);
ans = min(ans, dfs(u+1, s0, s1, s2)+c[u]);
return ans;
}
int main(){
string line;
int x;
bool flag = false;
while(getline(cin, line)){
stringstream ss(line);
ss >> s >> m >> n;
if(s == 0) break;
for(int i = 1; i <= m+n; i++) {
getline(cin, line);
stringstream ss(line);
ss >> c[i];
jiao[i] = 0;
while(ss >> x) jiao[i] |= (1<<(x-1));
}
//memset(dp, -1, sizeof(dp));
cls(dp, -1);
cout << dfs(1, (1<<s)-1, 0, 0) << "
";
}
return 0;
}
uva 1252 (状压dp)
最多11个特征,n个物品,问最多问多少次能一定确定一个物品。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 128+5;;
const int maxm = 11;
int d[1<<maxm][1<<maxm];
string feature[maxn];
bool vis[1<<maxm][1<<maxm];
int m, n;
int cnt[1<<maxm][1<<maxm];
int dp(int s, int a){
if(cnt[s][a]<=1) return 0;
if(cnt[s][a] == 2) return 1;
int &ans = d[s][a];
if(vis[s][a]) return ans;
vis[s][a] = true;
ans = inf;
for(int i=0; i<m; i++){
if(!(s&(1<<i))){
int s1 = s^(1<<i), a1 = a^(1<<i);
//增加一个i特征的询问
d[s][a] = min(d[s][a], (max(dp(s1, a1), dp(s1, a))+1));
}
}
return ans;
}
void init(){
for(int s=0; s<(1<<m); s++){
for(int a=s; a; a=(a-1)&s){
cnt[s][a] = 0;
}
cnt[s][0] = 0;
}
for(int i=0; i<n; i++){
int tot = 0;
for(int j=0; j<m; j++){
if(feature[i][j] == '1'){
tot += (1<<j);
}
}
for(int s=0; s<(1<<m); s++){
cnt[s][s&tot]++;
}
}
}
int main(){
ios::sync_with_stdio(false);
int kase = 1;
while(cin>>m>>n&&n+m){
for(int i=0; i<n; i++) cin>>feature[i];
init();
cls(vis, 0);
cout<<dp(0, 0)<<"
";
kase++;
}
return 0;
}
LCS 转化为LIS
两个序列中,每一个序列里面的数字都只出现了一次,因此可以来转化
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 250*250+10;
int a[maxn], b[maxn];
int c[maxn];
int n, p, q;
map<int, int> mp;
int g[maxn];
int d[maxn];
int main(){
ios::sync_with_stdio(false);
int kase = 1;
int _;
cin>>_;
while(_--){
cin>>n>>p>>q;
mp.clear();
for(int i=1; i<=p+1; i++) cin>>a[i], mp[a[i]] = i;
for(int i=1; i<=q+1; i++) cin>>b[i];
int idx = 1;
for(int i=1; i<=q+1; i++) if(mp[b[i]])c[idx++] = mp[b[i]];
// for(int i=1; i<=q; i++) cout<<b[i]<<" ";
// cout<<endl;
int ans = 0;
cls(g, 0x3f);
for(int i=1; i<idx; i++){
int k=lower_bound(g+1, g+idx, c[i])-g;
d[i] = k;
g[k] = c[i];
ans = max(ans, d[i]);
}
cout<<"Case "<<kase++<<": "<<ans<<endl;
}
return 0;
}
/*
1
10 7 8
1 7 5 4 8 3 9
1 4 3 5 6 2 8 9
*/
约瑟夫环
[f[i] = (f[i-1]+k)\%i
]
由于是从m号开始的,(f[n] = (m-k+1+f[n])\%n), 最后判断f[n]<=0是否成立,否则+n.
初始化(f[1] = 0)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 1e4+10;
int d[maxn];
int n, k, m;
int main(){
ios::sync_with_stdio(false);
while(cin>>n>>k>>m&&n+k+m){
d[1] = 0;
for(int i=2; i<=n; i++){
d[i] = (d[i-1]+k)%i;
}
d[n] = (m-k+1+d[n])%n;
if(d[n]<=0) d[n]+=n;
cout<<d[n]<<endl;
}
return 0;
}
博弈+dp
(dp[i][j]表示(i, j)区间先手的取的最大值)
时间复杂度是(O(n^2))
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 200+10;
int a[maxn];
int dp[maxn][maxn];
int z[maxn][maxn], y[maxn][maxn];
int n;
int pre[maxn];
int main(){
ios::sync_with_stdio(false);
while(cin>>n&&n){
for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) dp[i][j] = -inf;
for(int i=1; i<=n; i++){
cin>>a[i];
pre[i] = pre[i-1]+a[i];
}
for(int i=1; i<=n; i++) dp[i][i] = z[i][i] = y[i][i] = a[i];
for(int l=1; l<=n; l++){
for(int i=1; i<=n-l; i++){
int j=i+l;
int mi = 0;
mi = min(mi, y[i][j-1]);
mi = min(mi, z[i+1][j]);
dp[i][j] = max(dp[i][j], pre[j]-pre[i-1]-mi);
y[i][j] = min(y[i][j-1], dp[i][j]);
z[i][j] = min(z[i+1][j], dp[i][j]);
}
}
cout<<2*dp[1][n]-pre[n]<<endl;
}
return 0;
}
停掉最多的服务(状压dp)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 17;
int cover[1<<maxn];
int d[1<<maxn];
int graph[maxn];
int n;
int main(){
ios::sync_with_stdio(false);
int kase = 1;
while(cin>>n&&n){
int m;
cls(graph, 0);
cls(cover, 0);
for(int i=0; i<n; i++){
cin>>m;
int v;
graph[i] = (1<<i);
for(int j=0; j<m; j++) {
cin>>v;
graph[i] |= (1<<v);
}
}
for(int s=1; s<(1<<n); s++){
for(int i=0; i<n; i++){
if(s&(1<<i)){
cover[s] |= graph[i];
}
}
}
cls(d, 0);
d[0] = 0;
for(int s=1; s<(1<<n); s++){
for(int s0=s; s0; s0=(s0-1)&s){
if(cover[s0] == (1<<n)-1){
//s0已经可以停掉一个服务了,剩下接着找。
d[s] = max(d[s^s0]+1, d[s]);
}
}
}
cout<<"Case "<<kase++<<": "<<d[(1<<n)-1]<<endl;
}
return 0;
}
森林的最小点覆盖+最多的一条边被两点覆盖
树形dp
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 1000+10;
const int M = 2000;
vector<int> G[maxn];
int n, m;
bool vis[maxn][2];
int d[maxn][2];
int dp(int u, int state, int p){
if(vis[u][state]) return d[u][state];
vis[u][state] = true;
int &ans = d[u][state];
//点亮该灯
ans=M;
for(int i=0; i<G[u].size(); i++){
int v = G[u][i];
if(p!=v){
ans += dp(v, 1, u);
}
}
if(state == 0&&p>=0) ans++;
//不点该灯
if(p<0||state == 1){
int ans1=0;
for(int i=0; i<G[u].size(); i++){
int v = G[u][i];
if(p!=v){
ans1 += dp(v, 0, u);
}
}
if(p>=0) ans1++;
ans = min(ans, ans1);
}
//若父亲没点,这条边仅一次被点亮
return ans;
}
int main(){
ios::sync_with_stdio(false);
int _;
cin>>_;
while(_--){
cin>>n>>m;
int u, v;
for(int i=0; i<n; i++) G[i].clear(), d[i][0] = d[i][1] = 0, vis[i][0] = vis[i][1] = false;
for(int i=1;i<=m; i++){
cin>>u>>v;
G[u].push_back(v), G[v].push_back(u);
}
int ans = 0;
for(int i=0; i<n; i++){
if(!vis[i][0]){
ans += dp(i, 0, -1);
}
}
cout<<ans/2000<<" "<<m-(ans%2000)<<" "<<ans%2000<<endl;
}
return 0;
}
带有滑动窗口的线性dp
按序取垃圾,使得最后的经过的距离最短。
注意条件:垃圾重量是单调增的,所以可以使用滑动窗口。
uva的PE居然显示的是WA。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 1e5+10;
int C;
struct Node{
int x, y, weight;
}node[maxn];
int pre_dist[maxn];
int pre_weight[maxn];
int pre[maxn];
int n;
int d[maxn];
int q[maxn];
int get(int j){
return d[j]+abs(node[j+1].x)+abs(node[j+1].y)-pre[j+1];
}
int main(){
ios::sync_with_stdio(false);
int _;
cin>>_;
while(_--){
cin>>C;
cin>>n;
int x, y, w;
pre[0] = 0;
pre_weight[0] = pre_dist[0] = 0;
for(int i=1; i<=n; i++){
cin>>x>>y>>w;
node[i] = Node{x, y, w};
pre_weight[i] = pre_weight[i-1]+w;
pre[i] = pre[i-1]+abs(x-node[i-1].x)+abs(y-node[i-1].y);
}
int l, r;
l=r=1;
q[l] = 0;
cls(d, 0x3f);
d[0] = 0;
for(int i=1; i<=n; i++){
while(l<=r&&pre_weight[i]-pre_weight[q[l]]>C)l++;
d[i] = min(d[i], get(q[l]));
d[i] += (pre[i]+abs(node[i].x)+abs(node[i].y));
//cout<<i<<" "<<d[i]<<endl;
while(l<=r&&get(q[r])>=get(i))r--;
q[++r] = i;
}
cout<<d[n]<<endl;
if(_>0) cout<<endl;
}
return 0;
}
内否切割成目标的矩形块(状压dp)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 15;
int n, x, y;
int a[maxn];
int d[1<<maxn][105];
bool vis[1<<maxn][105];
int s[1<<maxn];
int cou(int x){
return x==0?0:cou(x/2)+(x&1);
}
int dp(int S, int x){
if(vis[S][x]) return d[S][x];
vis[S][x] = true;
int &ans = d[S][x];
if(cou(S) == 1) return ans = 1;
int y = s[S]/x;
for(int s1=(S-1)&S; s1; s1=(s1-1)&S){
int s2 = S-s1;
//沿y切
if(s[s1]%x == 0&&dp(s1, min(x, s[s1]/x))&&dp(s2, min(x, s[s2]/x))) return ans=1;
if(s[s1]%y == 0&&dp(s1, min(y, s[s1]/y))&&dp(s2, min(y, s[s2]/y))) return ans=1;
}
return ans=0;
}
int main(){
ios::sync_with_stdio(false);
int kase = 1;
while(cin>>n){
if(!n) break;
cls(vis, 0);
cin>>x>>y;
for(int i=0; i<n; i++) cin>>a[i];
cls(s, 0);
for(int i=0; i<(1<<n); i++){
for(int j=0; j<n; j++) if(i&(1<<j)) s[i] += a[j];
}
int ans = 0;
//cout<<s[(1<<n)-1]<<endl;
if(s[(1<<n)-1]!=x*y||s[(1<<n)-1]%x) ans = 0;
else ans = dp((1<<n)-1, min(x, y));
if(ans){
cout<<"Case "<<kase++<<": Yes"<<endl;
}
else{
cout<<"Case "<<kase++<<": No"<<endl;
}
}
return 0;
}
分割团队(正负背包)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 100+10;
bool vis[maxn];
int G[maxn][maxn];
int color[maxn];
vector<int> team[maxn][2];
int no;
int d[maxn][maxn<<1];
int diff[maxn];
int n;
bool dfs(int x, int col){
color[x] = col;
//cout<<x<<" "<<col<<endl;
team[no][col-1].push_back(x);
for(int i=1; i<=n; i++){
if(i == x) continue;
if(!(G[i][x]&&G[x][i])){
if(color[i] == col) return false;
if(!color[i]&&!dfs(i, 3-col)) return false;
}
}
return true;
}
bool build(){
cls(color, 0);
no = 0;
for(int i=1; i<=n; i++){
if(!color[i]){
team[no][0].clear(), team[no][1].clear();
if(!dfs(i, 1)) return false;
diff[no] = team[no][0].size()-team[no][1].size();
no++;
}
}
return true;
}
void prin(int ans){
vector<int> team1, team2;
for(int i=no-1; i>=0; i--){
int t;
//cout<<i<<" "<<ans<<endl;
if(d[i][ans+n-diff[i]]){
t=0;
ans -= diff[i];
}
else{
t =1;
ans += diff[i];
}
//cout<<ans<<endl;
for(int j=0; j<team[i][t].size(); j++){
team1.push_back(team[i][t][j]);
}
for(int j=0; j<team[i][t^1].size(); j++){
team2.push_back(team[i][t^1][j]);
}
}
cout<<team1.size();
for(int i=0; i<team1.size(); i++) cout<<" "<<team1[i];
cout<<endl;
cout<<team2.size();
for(int i=0; i<team2.size(); i++) cout<<" "<<team2[i];
cout<<endl;
}
void dp(){
cls(d, 0);
d[0][0+n] = 1;
for(int i=0; i<no; i++){
for(int j=-n; j<=n; j++) if(d[i][j+n]){
d[i+1][j+n+diff[i]] = 1;
d[i+1][j+n-diff[i]] = 1;
}
}
for(int ans = 0; ans<=n; ans++){
if(d[no][ans+n]) {prin(ans); return;}
if(d[no][-ans+n]) {prin(-ans); return;}
}
}
int main(){
ios::sync_with_stdio(false);
int _;
cin>>_;
while(_--){
cin>>n;
cls(G, 0);
for(int i=1; i<=n; i++){
int id;
while(cin>>id&&id){
G[i][id] = 1;
}
}
if(n==1||!build()) cout<<"No solution
";
else{
dp();
}
if(_) cout<<"
";
}
return 0;
}
/*
2
5
3 4 5 0
1 3 5 0
2 1 4 5 0
2 3 5 0
1 2 3 4 0
5
2 3 5 0
1 4 5 3 0
1 2 5 0
1 2 3 0
4 3 2 1 0
*/
兑换货币(正负背包)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include <unordered_map>
#include <unordered_set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)
const int inf = 0x3f3f3f3f;
const int maxn = 2000+10;
int num[10];
int dp[maxn];
int main(){
ios::sync_with_stdio(false);
int _;
scanf("%d", &_);
while(_--){
for(int i=1; i<=6; i++) scanf("%d", &num[i]);
for(int i=1; i<=2000; i++) dp[i] = inf;
dp[0] = 0;
for(int i=1; i<=6; i++){
for(int j=num[i]; j<=2000; j++){
dp[j] = min(dp[j], dp[j-num[i]]+1);
}
}
for(int i=1; i<=6; i++){
for(int j=2000-num[i]; j>=0; j--){
dp[j] = min(dp[j], dp[j+num[i]]+1);
}
}
int ans = 0;
int mx = -1;
for(int i=1;i<=100; i++){
mx = max(mx, dp[i]);
ans += dp[i];
}
printf("%.2lf %d
", double(ans)/100.0, mx);
}
return 0;
}