【题目】
http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1003
【算法分析】
F[i,j]表示从时间i到时间j完成运送所需要的最小代价。
然后F[i,j]可以利用spfa预处理。就是把不能用的点相关的边删掉,然后最短路之。
然后F[i,j]=min(F[i][k]+F[k+1][j]+cost,F[i,j])
【CODE】
#include
【题目】
http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1003
【算法分析】
F[i,j]表示从时间i到时间j完成运送所需要的最小代价。
然后F[i,j]可以利用spfa预处理。就是把不能用的点相关的边删掉,然后最短路之。
然后F[i,j]=min(F[i][k]+F[k+1][j]+cost,F[i,j])
【CODE】
#include
【算法分析】
这个要想想。。。
首先我们注意到,必然有一条竖线或者横线把3个矩形分成一边一个,一边两个的情况,于是预处理,然后再分类讨论即可。。。
【CODE】
#include
int m,n,k;
int w[N][N],sum[N][N],lu1[N][N],rd1[N][N];
int ru1[N][N],ld1[N][N],lu2m[N],lu2n[N],rd21[N],rd22[N];
inline int max(int x,int y){
if (x>y) return x;
return y;
}
void input(){
scanf("%d%d%d",&m,&n,&k);
int i,j;
for (i=1;i<=m;i++)
for (j=1;j<=n;j++) scanf("%d",&w[i][j]);
memset(rd21,200,sizeof(rd21));
memset(lu2m,200,sizeof(lu2m));
memset(rd22,200,sizeof(rd22));
memset(lu2n,200,sizeof(lu2n));
memset(lu1,200,sizeof(lu1));
memset(rd1,200,sizeof(rd1));
memset(ld1,200,sizeof(ld1));
memset(ru1,200,sizeof(ru1));
}
void change(){
int i,j;
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+w[i][j];
m=m-k+1; n=n-k+1;
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
w[i][j]=sum[i+k-1][j+k-1]-sum[i-1][j+k-1]-sum[i+k-1][j-1]+sum[i-1][j-1];
}
void init(){
int i,j;
for (i=1;i<=m;i++)
for (j=1;j<=n;j++){
lu1[i][j]=max(lu1[i-1][j],lu1[i][j-1]);
lu1[i][j]=max(lu1[i][j],w[i][j]);
}
for (i=m;i>=1;i–)
for (j=n;j>=1;j–){
rd1[i][j]=max(rd1[i+1][j],rd1[i][j+1]);
rd1[i][j]=max(rd1[i][j],w[i][j]);
}
for (i=1;i<=m;i++)
for (j=n;j>=1;j–){
ru1[i][j]=max(ru1[i-1][j],ru1[i][j+1]);
ru1[i][j]=max(ru1[i][j],w[i][j]);
}
for (i=m;i>=1;i–)
for (j=1;j<=n;j++){
ld1[i][j]=max(ld1[i+1][j],ld1[i][j-1]);
ld1[i][j]=max(ld1[i][j],w[i][j]);
}
//处理lu
for (j=1;j<=n;j++){
int &t=lu2m[j];
t=lu2m[j-1];
for (i=1;i<=m;i++){
if (i>k) t=max(t,lu1[i-k][j]+w[i][j]);
if (j>k) t=max(t,lu1[m][j-k]+w[i][j]);
if (i+k<=m) t=max(t,ld1[i+k][j]+w[i][j]);
}
}
for (i=1;i<=m;i++){
int &t=lu2n[i];
t=lu2n[i-1];
for (j=1;j<=n;j++){
if (j>k) t=max(t,lu1[i][j-k]+w[i][j]);
if (i>k) t=max(t,lu1[i-k][n]+w[i][j]);
if (j+k<=n) t=max(t,ru1[i][j+k]+w[i][j]);
}
}
//处理rd
for (j=n;j>=1;j–){
int &t=rd21[j];
t=rd21[j+1];
for (i=1;i<=m;i++){
if (i>k) t=max(t,ru1[i-k][j]+w[i][j]);
if (j+k<=n) t=max(t,rd1[1][j+k]+w[i][j]);
if (i+k<=m) t=max(t,rd1[i+k][j]+w[i][j]);
}
}
for (i=m;i>=1;i–){
int &t=rd22[i];
t=rd22[i+1];
for (j=1;j<=n;j++){
if (j+k<=n) t=max(t,rd1[i][j+k]+w[i][j]);
if (i+k<=m) t=max(t,rd1[i+k][1]+w[i][j]);
if (j>k) t=max(t,ld1[i][j-k]+w[i][j]);
}
}
}
void work(){
int ans=0,i,j;
for (i=1;i+k<=m;i++){
ans=max(ans,lu1[i][n]+rd22[i+k]);
ans=max(ans,lu2n[i]+rd1[i+k][1]);
}
for (j=1;j+k<=n;j++){
ans=max(ans,lu1[m][j]+rd21[j+k]);
ans=max(ans,lu2m[j]+rd1[1][j+k]);
}
printf("%dn",ans);
}
int main(){
freopen("oil.in","r",stdin);
freopen("oil.out","w",stdout);
input();
change();
init();
work();
}
【算法分析】
很简单,属于送分题类型。。。
缩点然后topsort+dp就可以了~
但是比较纠结的是会爆栈。。。。比赛不知道会不会的?听说Linux的栈比较大吧。。。
【CODE】
#include
const int INF=1000000000;
struct gtp{int x,y,next;}g[N];
int n,e,tot,S,head,tail,ans,stack;
int ls[N],fa[N],color[N],dep[N],list[N],du[N],w[N],F[N],v[N],edge[N],p[N];
bool ed[N];
inline void addedge(int x,int y){
e++;
g[e].x=x; g[e].y=y; g[e].next=ls[x]; ls[x]=e;
}
void input(){
int m,x,y;
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
addedge(x,y);
}
for (int i=1;i<=n;i++) scanf("%d",&w[i]);
int num;
scanf("%d%d",&S,&num);
for (int i=1;i<=num;i++){
scanf("%d",&x);
ed[x]=true;
}
}
int gf(int k){
if (fa[k]==k) return k;
fa[k]=gf(fa[k]);
return fa[k];
}
void dfs(int k){
/*
for (int t=ls[k];t;t=g[t].next)
if (!dep[g[t].y]){
dep[g[t].y]=dep[k]+1;
dfs(g[t].y);
if (dep[gf(g[t].y)]
if (!color[gf(g[t].y)] && dep[gf(g[t].y)]
color[k]=1;
*/
stack=1; p[1]=k; edge[1]=ls[k];
while (stack){
int &t=edge[stack];
if (!t){
color[p[stack]]=1;
stack–;
continue;
}
if (!dep[g[t].y]){
dep[g[t].y]=dep[g[t].x]+1;
stack++;
p[stack]=g[t].y;
edge[stack]=ls[g[t].y];
}else
if (!color[gf(g[t].y)] && dep[gf(g[t].y)]
edge[stack]=g[edge[stack]].next;
}else edge[stack]=g[edge[stack]].next;
}
}
void tarjan(){
for (int i=1;i<=n;i++){
fa[i]=i;
color[i]=0;
dep[i]=0;
}
for (int i=1;i<=n;i++)
if (!dep[i]){
dep[i]=1;
dfs(i);
}
for (int i=1;i<=n;i++){
gf(i);
if (fa[i]!=i){
w[fa[i]]+=w[i];
if (ed[i]) ed[fa[i]]=true;
}
}
}
void changegraph(){
int te=e;
e=0; memset(ls,0,sizeof(ls));
for (int i=1;i<=te;i++)
if (fa[g[i].x]!=fa[g[i].y])
addedge(fa[g[i].x],fa[g[i].y]);
}
void topsort(){
memset(du,0,sizeof(du));
head=0; tail=0;
for (int i=1;i<=e;i++) du[g[i].y]++;
for (int i=1;i<=n;i++)
if (fa[i]==i && !du[i]) list[++tail]=i;
while (head
for (int t=ls[list[head]];t;t=g[t].next){
du[g[t].y]–;
if (!du[g[t].y]) list[++tail]=g[t].y;
}
}
}
void dp(){
memset(v,0,sizeof(v));
for (int i=1;i<=n;i++) F[i]=-INF;
ans=0;
head=1;
while (list[head]!=fa[S]) head++;
F[fa[S]]=0;
for (int k=head;k<=tail;k++){
int &i=list[k];
if (F[i]==-INF) continue;
F[i]+=w[i];
for (int t=ls[i];t;t=g[t].next)
if (v[g[t].y]!=i){
v[g[t].y]=i;
if (F[i]>F[g[t].y]) F[g[t].y]=F[i];
}
if (ed[i] && F[i]>ans) ans=F[i];
}
printf("%dn",ans);
}
int main(){
freopen("atm.in","r",stdin);
freopen("atm.out","w",stdout);
input();
tarjan();
changegraph();
topsort();
dp();
}
【题目大意】
给定一个数组A[i],1<=a[i]<=10000
求把它分成M份,每份的和不超过一个值K。
问K最小是多少?
【算法分析】
注意到A[i]都是正数,所以我们可以二分答案,然后线性贪心判断即可。
如果A[i]存在负数的话,这个算法就不正确了。
【其它】
1WA,1A。悲剧,忘了删文件。
另外一开始想了挺久的。。。最主要是读题不够仔细,没看到那个A[i]>=1
【CODE】
#include
int m,n;
int a[101111],Max=0;
bool flag(LL limit){
int num=1;
LL sum=a[1];
for (int i=2;i<=n;i++)
if (sum+a[i]>limit){
num++;
sum=a[i];
}
else sum+=a[i];
if (num>m) return false;
return true;
}
int main(){
scanf("%d%d",&n,&m);
LL sum=0;
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
if (a[i]>Max) Max=a[i];
sum+=a[i];
}
LL l=Max,r=sum,mid;
while (l
if (flag(mid)) r=mid;
else l=mid+1;
}
printf("%lldn",l);
}
【题目大意】
同银河英雄传说。。。
【算法分析】
并差集之~
这题更简单,直接输出s[i]即可。
【其它】1A
。。。无意水,是在找银河英雄传说的提交网站时无意碰到的。。。
【CODE】
#include
int T;
int f[31111],s[31111],tail[31111];
char c;
int gf(int x){
if (f[x]==x) return x;
int tf=gf(f[x]);
s[x]+=s[f[x]];
f[x]=tf;
return tf;
}
void Union(){
int x,y;
scanf("%d%d",&y,&x);
gf(x); gf(y);
s[f[y]]=1;
int fy=f[y];
f[f[y]]=tail[f[x]];
tail[f[x]]=tail[fy];
}
void Count(){
int x;
scanf("%d%d",&x);
gf(x);
printf("%dn",s[x]);
}
int main(){
for (int i=1;i<=n;i++){
f[i]=i;
s[i]=0;
tail[i]=i;
}
scanf("%d",&T);
for (int i=1;i<=T;i++){
c=getchar();
while (c==’ ‘ || c==’n’) c=getchar();
if (c==’M’) Union();
else Count();
}
}