coi 2013-2014 round 5 domine
2014-12-26 20:01
239 查看
对于这样一个问题我们可以这样来看,对于棋盘的一个点,假如在这个地方放一个骨牌,那么它能对那些造成影响呢?很明显它会对与这个点相邻的点造成影响。
这样我们把棋盘上的点黑白染色,黑点向白点连边,费用为负权值和,流量为1,这样我们就把这个问题转化成了最小费用最大流的问题,然后再设一个点向超级起点建一个流量为K的边。这样就能确保我们最多会放K个。
所以最小费用最大流可以解决这个问题。
接下来算下空间时间
一共有4N+3个点,大概8N的边,而由于是二分图,所以最小费用最大流速度会很快。
还有另外一种算法。
定义状态 F[I][J][K],表示前i行,放J个,当前行的状态为K对后面的影响,这样我们可以使用状态压缩DP来做。
一位大牛的代码,我考试的时候只写了费用流。
这样我们把棋盘上的点黑白染色,黑点向白点连边,费用为负权值和,流量为1,这样我们就把这个问题转化成了最小费用最大流的问题,然后再设一个点向超级起点建一个流量为K的边。这样就能确保我们最多会放K个。
所以最小费用最大流可以解决这个问题。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define N 10000 #define ll long long using namespace std; int p=1; ll ans; int map [4],n,dian [4],dui [4],bj [4],zai [10]; int head ,use ,dis ,que ,tot,s,t,s1,k; struct data { int go,next,wgt,f; }edge[200000]; struct hh { int f,da,num; }jj ; void build(int a,int b,int c,int d) { p++; edge[p].go=b; edge[p].next=head[a]; head[a]=p; edge[p].wgt=c; edge[p].f=d; } void addedge(int a,int b,int c,int d) { build(a,b,c,d); build(b,a,-c,0); } void up() { int k=jj[t].da; for (int i=t;i!=s1;i=jj[i].f) { int node=jj[i].num; edge[node].f-=k; edge[node^1].f+=k; } } int spfa() { int tou=1,wei=1; memset(use,0,sizeof(use)); for (int i=1;i<=t;i++) dis[i]=-1000000000; que[1]=s1; use[s1]=1; dis[s1]=0; jj[s1].da=12345678; for (;tou<=wei;tou++) { int node=que[tou%N]; for (int i=head[node];i;i=edge[i].next) { if (dis[node]+edge[i].wgt>dis[edge[i].go]&&edge[i].f>0) { dis[edge[i].go]=dis[node]+edge[i].wgt; jj[edge[i].go].f=node; jj[edge[i].go].da=min(jj[node].da,edge[i].f); jj[edge[i].go].num=i; if (!use[edge[i].go]) { use[edge[i].go]=1; wei++; que[wei%N]=edge[i].go; } } } use[node]=0; } return dis[t]; } int main() { freopen("domine.in","r",stdin); freopen("domine.out","w",stdout); scanf("%d%d",&n,&k); s1=9002; s=9000; t=s+1; addedge(s1,s,0,k); for (int i=1;i<=n;i++) for (int j=1;j<=3;j++) scanf("%d",&map[i][j]); for (int i=1;i<=n;i++) for (int j=1;j<=3;j++) { dui[i][j]=++tot; dian[i][j]=++tot; addedge(dui[i][j],dian[i][j],0,1); } for (int i=1;i<=n;i++) { if (i%2) bj[i][1]=1; else bj[i][1]=0; for (int j=2;j<=3;j++) bj[i][j]=bj[i][j-1]^1; } for (int i=1;i<=n;i++) for (int j=1;j<=3;j++) zai[i][j]=1; for (int i=1;i<=n;i++) for (int j=1;j<=3;j++) { if (bj[i][j]==1) { if (zai[i][j+1]) addedge(dian[i][j],dui[i][j+1],map[i][j]+map[i][j+1],1); if (zai[i][j-1]) addedge(dian[i][j],dui[i][j-1],map[i][j]+map[i][j-1],1); if (zai[i+1][j]) addedge(dian[i][j],dui[i+1][j],map[i][j]+map[i+1][j],1); if (zai[i-1][j]) addedge(dian[i][j],dui[i-1][j],map[i-1][j]+map[i][j],1);<span style="font-family: Arial, Helvetica, sans-serif;"> addedge(s,dian[i][j],0,1);</span>
} else { addedge(dian[i][j],t,0,1); } } int time=0; while (1) { int x=spfa(); time++; if (time==k+1) break; ans=ans+(ll)(x); up(); } printf("%I64d\n",ans); return 0; }代码很丑。
接下来算下空间时间
一共有4N+3个点,大概8N的边,而由于是二分图,所以最小费用最大流速度会很快。
还有另外一种算法。
定义状态 F[I][J][K],表示前i行,放J个,当前行的状态为K对后面的影响,这样我们可以使用状态压缩DP来做。
一位大牛的代码,我考试的时候只写了费用流。
<pre name="code" class="cpp">#include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=1000+10,lolo=0X7fffffff-1; int n,kk,now,A,B,C; int map[maxn][3]; int f[maxn][maxn][8]; void gengxin(int w,int zhi,int ge,int now){ if (ge+B>kk) return; if (w>3){ //如果当前的位置大于3,则直接更新; f[A+1][B+ge][now]=max(f[A+1][B+ge][now],f[A][B][C]+zhi); return; } if ((C>>(w-1))&1) gengxin(w+1,zhi,ge,now);//如果当前是1则不更新下一位置因为不会对后面造成影响。否则就求出对下面的影响。 else{ if (w<=2&&(!((C>>w)&1))) gengxin(w+2,zhi+map[A][w]+map[A][w+1],ge+1,now); gengxin(w+1,zhi+map[A][w]+map[A+1][w],ge+1,now|(1<<(w-1)));//放牌。 gengxin(w+1,zhi,ge,now);//不放。 } } void chuli(){ for(int i=0;i<=n;i++) for (int j=0;j<=kk;j++) for (int k=0;k<=7;k++) if(f[i][j][k]!=-lolo) { A=i;B=j;C=k; gengxin(1,0,0,0); } } void pretreatment(){ for (int i=0;i<maxn;i++) for (int j=0;j<maxn;j++) for (int k=0;k<8;k++) f[i][j][k]=-lolo; f[0][0][7]=0; } void reading(){ scanf("%d%d",&n,&kk); for (int i=1;i<=n;i++) for (int j=1;j<=3;j++)scanf("%d",&map[i][j]); } int main(){ freopen("domine.in","r",stdin); freopen("domine.out","w",stdout); reading(); pretreatment(); chuli(); printf("%d",f[n+1][kk][0]); return 0; }
相关文章推荐
- coi 2013-2014 round 5 trokuti
- COCI 2013/2014 1st round, September 28th, 2013 解题报告
- ACM ICPC 2013-2014 E. The Emperor’s plan(组合数学+dp)
- Google Code Jam 2014 Round 1B Problem B
- 再见2013,你好2014
- 程序媛的2013总结以及2014展望
- [题解+总结]NOIP2013-2014提高组题目浅析
- MyEclipse 10, 2013, 2014 破解、注册码
- LA6576 VivoParc (2013-2014 ACM-ICPC Southwestern Europe Regional Contest G题) 搜索
- 2013-2014 ACM-ICPC, NEERC, Southern Subregional Contest Problem H. Password Service dp
- Opencv 完美配置攻略 2014 (Win8.1 + Opencv 2.4.8 + VS 2013)上
- 2014 GCJ Round 1B New Lottery Game(数位dp,x小于等于A,y小于等于B,并且x&y值小于等于K的数字个数)
- 2013-2014 ACM-ICPC Brazil Subregional Programming Contest
- Google China New Grad Test 2014 Round A Problem D
- 2013总结 和2014期望
- Croc Champ 2013 - Round 2 (Div. 2 Edition) 贪心+ 搜索+剪枝 + 数学
- Google CodeJam Round 1A 2013
- Practice Round China New Grad Test 2014
- 中山大学 2013-2014 校历
- 2013-2014集训第二次个人积分赛