poj3254:
Corn Fields
Time Limit: 2000 MS Memory Limit: 65536 KB
64-bit integer IO format: %I64d , %I64u Java class name: Main
Description
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.
Input
Lines 2.. M+1: Line i+1 describes row i of the pasture with N space-separated integers indicating whether a square is fertile (1 for fertile, 0 for infertile)
Output
Sample Input
2 3 1 1 1 0 1 0
Sample Output
9
题意:有些在帝能够放牧,有些不行,放牧的地方不能相邻,文有多少种方案
思路:状态压缩,dp[i][j]表示,到第i行,状态为j的有多少种方法。可以手先预处理出每一行合法的状态,对于当前的行,只需要判断这个状态跟前一行的状态不冲突,就加上
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=5010;
const int MOD=100000000;
int N,M;
int dp[15][maxn];
int A[maxn];
int cnt;
int val[maxn];
bool can(int x)
{
return (x&(x<<1))==0;
}
bool judge(int x,int cur)
{
return (x&(val[cur]))==0;
}
int main()
{
while(scanf("%d%d",&M,&N)!=EOF)
{
cnt=0;
for(int i=0;i<(1<<N);i++)
if(can(i))A[++cnt]=i;
memset(dp,0,sizeof(dp));
memset(val,0,sizeof(val));
for(int i=1;i<=M;i++)
{
int x;
for(int j=1;j<=N;j++)
{
scanf("%d",&x);
//反着加,方便后面判断不合法的状态
if(!x)val[i]+=(1<<(N-j));
}
}
for(int i=1;i<=cnt;i++)
if(judge(A[i],1))dp[1][i]=1;
for(int i=2;i<=M;i++)
{
for(int j=1;j<=cnt;j++)
{
if(!judge(A[j],i))continue;
for(int k=1;k<=cnt;k++)
{
if(!judge(A[k],i-1))continue;
if(A[j]&A[k])continue;//跟前一行的状态不冲突,也就是不相邻
dp[i][j]=(dp[i][j]+dp[i-1][k])%MOD;
}
}
}
int ans=0;
for(int i=1;i<=cnt;i++)
ans=(ans+dp[M][i])%MOD;
printf("%d\n",ans);
}
return 0;
}
HRBUST 1475
G - 国王的宴会 HRBUST 1475
Time Limit: 1000 MS Memory Limit: 65536 KB
64-bit integer IO format: %lld , %llu Java class name: Main
Description
C国在成果破解J国破坏交通的阴谋之后,国王决定宴请各位大臣,合理制定宴请的人的名单的任务就交给了作为国王智囊团团长的你。
你知道国王喜欢热闹,所以你希望能邀请尽量多的人,但是做为直接上下级关系的两个人直接出现在宴会上的时候会显得很尴尬,所以不能同时请有上下级关系的两个人。
国王是宴会的主办方,也是这个王国的最高领袖,所以必须到场。
为了能为宴会准备的更好,你需要知道整个宴会最多可以邀请多少宾客。
Input
有多组测试数据。
每组数据的第一行两个整数n(n<=1000)和m分别表示整个王国的官员的数量和上下级关系的数量。
接下来m行每行两个整数a和b表示b是a的直接下级。
处理到文件结束。
Output
输出一个整数表示包括国王在内的宴会能邀请的人数最多的数量。
Sample Input
5 4
5 3
3 4
4 1
4 2
Sample Output
3
树形dp,dp[u][0]表示以u为根,不选u的最佳答案,dp[u][1]则表示选的最佳答案
dp[u][0]+=max(dp[v][0],dp[v][1]);
dp[u][1]+=dp[v][0];
其中v是u的孩子节点
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=10010;
int N,M;
int in[maxn];
int root;
int dp[maxn][2];
int head[maxn],tot;
struct node
{
int v,next;
}edge[maxn];
void add_edge(int u,int v)
{
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void DP(int u)
{
dp[u][0]=0,dp[u][1]=1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
DP(v);
dp[u][0]+=max(dp[v][0],dp[v][1]);
dp[u][1]+=dp[v][0];
}
}
int main()
{
while(scanf("%d%d",&N,&M)!=EOF)
{
memset(in,0,sizeof(in));
memset(head,-1,sizeof(head));
tot=0;
for(int i=1;i<=M;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
in[v]++;
}
for(int i=1;i<=N;i++)
if(!in[i]){root=i;break;}
DP(root);
printf("%d\n",dp[root][1]);
}
return 0;
}
HRBUST 1477
F - 战争与守卫 HRBUST 1477
Time Limit: 1000 MS Memory Limit: 65536 KB
64-bit integer IO format: %lld , %llu Java class name: Main
Description
J国和C国爆发了战争,J国派出了很多间谍深入到C国内部,经常在C国的城市之间炸毁道路,阻拦C国的军队,C国为了抓到这些间谍,需要派人在城市进行监视,一个城市只要有一个人监视,那么这个城市的所有的道路也都会被监视到,为了能够尽量多的士兵去前线打仗,监视的士兵要尽可能的少,希望靠你编程求出至少需要多少人能实现对所有城市之间道路的监视。
Input
有多组测试数据
每组测试数据的第一行,一个整数n表示C国城市的数量(编号为0-----n-1) n<=2000
接下来n行:i:(M)表示有M个城市和城市i之间有道路连通,然后是M个整数表示和i连通的城市的编号。
处理到文件结束,输入数据保证是一棵树。
Output
输出一个整数,表示至少需要多少士兵能实现对所有道路的监视。
Sample Input
4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
Sample Output
1
跟上一个题差不多,分两种情况,也就是这个节点放或者不方,取最大值
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=2010;
int N,M;
vector<int> g[maxn];
int vis[maxn][2];
int dp[maxn][2];
int DP(int i,int j,int f)
{
if(vis[i][j])return dp[i][j];
vis[i][j]=1;
int &ans=dp[i][j];
ans=1;
for(int k=0;k<g[i].size();k++)
{
int v=g[i][k];
if(v!=f)ans+=DP(v,1,i);
}
if(j||f<0)//如果这个点的父节点放了或者这个点是根节点,可以选择不方
{
int sum=0;
for(int k=0;k<g[i].size();k++)
{
int v=g[i][k];
if(v!=f)sum+=DP(v,0,i);
}
ans=min(ans,sum);
}
return ans;
}
int main()
{
while(scanf("%d",&N)!=EOF)
{
int u,v,num;
for(int i=0;i<=N;i++)g[i].clear();
for(int i=1;i<=N;i++)
{
scanf("%d:(%d)",&u,&num);
for(int j=0;j<num;j++)
{
scanf("%d",&v);
g[u].push_back(v);
g[v].push_back(u);
}
}
int ans=0;
memset(vis,0,sizeof(vis));
for(int i=0;i<N;i++)
if(!vis[i][0])
ans+=DP(i,0,-1);
printf("%d\n",ans);
}
return 0;
}
HRBUST 1473
E - 教主的遗产 HRBUST 1473
Time Limit: 1000 MS Memory Limit: 65536 KB
64-bit integer IO format: %lld , %llu Java class name: Main
Description
恭送教主!
教主在2012年7月19日上午10:48,坐上前往北京的火车,从此开始了高富帅的生活。
设Sij表示第i题在第j题做完后才做获得的AC系数,有三道题a, b, c,做题顺序为bac,则系数和为:Sum = Sab + Scb + Sca。
Input
Output
Sample Input
1
0
2
0 2
4 0
3
0 2 4
4 0 25
17 15 0
Sample Output
0
4
46
dp[i][j]表示到达状态j,最后一个做的题是i的最大值
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
int a[20][20],dp[(1<<16)],N;
int main()
{
while(scanf("%d",&N)!=EOF)
{
memset(dp,-1,sizeof(dp));
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
scanf("%d",&a[i][j]);
for(int i=0;i<N;i++)
dp[(1<<i)]=0;
for(int st=1;st<(1<<N)-1;st++)
{
for(int i=0;i<N;i++)
{
if(st&(1<<i)) continue;
int tmp=0;
for(int j=0;j<N;j++)
if(st&(1<<j))
tmp+=a[i][j];
dp[(st|(1<<i))]=max(dp[(st|(1<<i))],dp[st]+tmp);
}
}
printf("%d\n",dp[(1<<N)-1]);
}
return 0;
}
ZOJ3662
H - Math Magic ZOJ 3662
Time Limit: 3000 MS Memory Limit: 32768 KB
64-bit integer IO format: %lld , %llu Java class name: Main
Description
Yesterday, my teacher taught us about math: +, -, *, /, GCD, LCM... As you know, LCM (Least common multiple) of two positive numbers can be solved easily because of a * b = GCD (a, b) * LCM (a, b).
In class, I raised a new idea: "how to calculate the LCM of K numbers". It's also an easy problem indeed, which only cost me 1 minute to solve it. I raised my hand and told teacher about my outstanding algorithm. Teacher just smiled and smiled...
After class, my teacher gave me a new problem and he wanted me solve it in 1 minute, too. If we know three parameters N, M, K, and two equations:
1. SUM (A1, A2, ..., Ai, Ai+1,..., AK) = N
2. LCM (A1, A2, ..., Ai, Ai+1,..., AK) = M
Can you calculate how many kinds of solutions are there for Ai (Ai are all positive numbers). I began to roll cold sweat but teacher just smiled and smiled.
Can you solve this problem in 1 minute?
Input
There are multiple test cases.
Each test case contains three integers N, M, K. (1 ≤ N, M ≤ 1,000, 1 ≤ K ≤ 100)
Output
For each test case, output an integer indicating the number of solution modulo 1,000,000,007(1e9 + 7).
You can get more details in the sample and hint below.
Sample Input
4 2 2 3 2 2
Sample Output
1 2
Hint
The first test case: the only solution is (2, 2).
The second test case: the solution are (1, 2) and (2, 1).
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=1010;
const int MOD=1e9+7;
int N,M,K,cnt;
int LCM[maxn][maxn];
int num[maxn],pos[maxn];
int dp[2][maxn][maxn/10];
int main()
{freopen("in.txt","r",stdin);
for(int i=1;i<=1000;i++)
for(int j=1;j<=1000;j++)
LCM[i][j]=i/__gcd(i,j)*j;
while(scanf("%d%d%d",&N,&M,&K)!=EOF)
{
cnt=0;
memset(pos,-1,sizeof(pos));
for(int i=1;i<=M;i++)
if(M%i==0)num[cnt]=i,pos[i]=cnt++;
memset(dp[0],-1,sizeof(dp[0]));
dp[0][0][0]=1;
for(int i=1;i<=K;i++)
{
memset(dp[i&1],-1,sizeof(dp[i&1]));
for(int j=i-1;j<=N;j++)
{
for(int k=0;k<cnt;k++)
{
if(dp[(i+1)&1][j][k]==-1)continue;
for(int r=0;r<cnt&&j+num[r]<=N;r++)
{
int l=j+num[r];
int s=LCM[num[r]][num[k]];
if(s<=M&&pos[s]!=-1)
{
s=pos[s];
if(dp[i&1][l][s]==-1)dp[i&1][l][s]=0;
dp[i&1][l][s]+=dp[(i+1)&1][j][k];
if(dp[i&1][l][s]>=MOD)dp[i&1][l][s]-=MOD;
}
}
}
}
}
printf("%d\n",dp[K&1][N][pos[M]]==-1?0:dp[K&1][N][pos[M]]);
}
return 0;
}