题目:https://loj.ac/problem/2557

第一个点可以暴搜。

第三个点无依赖关系,k=3,可以 DP 。dp[ cr ][ i ][ j ] 表示前 cr 个任务、第一台机器最晚完成时间是 i 、第二台机器最晚完成时间是 j ,第三台机器最晚完成时间是多少。数组开 500 就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
const int N=,M=,K=,INF=1e9+;
int n,m,k,op,dp[N][M][M],pr[N][M][M][];
int t[N][K],r[K][K],prn[N];
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&op);
for(int i=;i<=n;i++)
for(int j=;j<=k;j++)
scanf("%d",&t[i][j]);
for(int i=;i<=k;i++)
for(int j=;j<=k;j++)
scanf("%d",&r[i][j]);
memset(dp,0x3f,sizeof dp);
dp[][][]=;
for(int cr=;cr<=n;cr++)
for(int i=;i<=;i++)
for(int j=;j<=;j++)
{
int w=t[cr][];
dp[cr][i][j]=dp[cr-][i][j]+w;
pr[cr][i][j][]=i; pr[cr][i][j][]=j;
w=t[cr][];
if(i>=w&&dp[cr-][i-w][j]<dp[cr][i][j])
{
dp[cr][i][j]=dp[cr-][i-w][j];
pr[cr][i][j][]=i-w; pr[cr][i][j][]=j;
}
w=t[cr][];
if(j>=w&&dp[cr-][i][j-w]<dp[cr][i][j])
{
dp[cr][i][j]=dp[cr-][i][j-w];
pr[cr][i][j][]=i; pr[cr][i][j][]=j-w;
}
}
int ans=INF,r0,r1;
for(int i=;i<=;i++)
for(int j=;j<=;j++)
{
int d=Mx(Mx(i,j),dp[n][i][j]);
if(d<ans)ans=d,r0=i,r1=j;
}
for(int i=n;i;i--)
{
int t0=pr[i][r0][r1][],t1=pr[i][r0][r1][];
if(t0!=r0)prn[i]=; else if(t1!=r1)prn[i]=; else prn[i]=;
r0=t0; r1=t1;
}
for(int i=;i<=n;i++)printf("%d ",prn[i]);puts("");
return ;
}

第四个点连成三条编号有序的链 。 dp[ i ][ j ] 表示前 i 个任务、此刻在 j 点,最小时间总和。链断开的位置不用算“传输时间”即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
const int N=,K=,INF=1e9+;
int n,m,k,op,a[N],prn[N];
int t[N][K],r[K][K],dp[N][K],pr[N][K];
bool vis[N];
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&op);
for(int i=,u,v;i<=m;i++)
scanf("%d%d",&u,&v);
for(int i=;i<=n;i++)
for(int j=;j<=k;j++)
scanf("%d",&t[i][j]);
for(int i=;i<=k;i++)
for(int j=;j<=k;j++)
scanf("%d",&r[i][j]);
for(int j=;j<=k;j++)
dp[][j]=t[][j];
for(int i=;i<=n;i++)
{
if(i==||i==)
{
int rt=;
for(int l=;l<=k;l++)
if(dp[i-][l]<dp[i-][rt])rt=l;
for(int j=;j<=k;j++)
{
dp[i][j]=t[i][j]+dp[i-][rt];
pr[i][j]=rt;
}
continue;
}
for(int j=;j<=k;j++)
{
dp[i][j]=INF;
for(int l=;l<=k;l++)
if(dp[i-][l]+r[l][j]<dp[i][j])
{
dp[i][j]=dp[i-][l]+r[l][j];
pr[i][j]=l;
}
dp[i][j]+=t[i][j];
}
}
int ans=;
for(int j=;j<=k;j++)if(dp[n][j]<dp[n][ans])ans=j;
for(int i=n;i;i--)
prn[i]=ans,ans=pr[i][ans];
for(int i=;i<=n;i++)printf("%d ",prn[i]);puts("");
return ;
}

第七个点,发现每个任务在每个机器上的时间差不多,所以(看别人博客)发现方案应该是二分图匹配。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=,K=,M=N*K;
int n,m,k,op,lm=,hd[N],xnt,to[M],nxt[M],per[K],prn[N];
int t[N][K],r[K][K]; bool vis[K];
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
bool xyl(int cr)
{
for(int i=hd[cr],v;i;i=nxt[i])
if(!vis[v=to[i]])
{
vis[v]=;
if(!per[v]||xyl(per[v]))
{ per[v]=cr; return true;}
}
return false;
}
int main()
{
n=rdn();m=rdn();k=rdn();op=rdn();
for(int i=;i<=n;i++)
for(int j=;j<=k;j++) t[i][j]=rdn();
for(int i=;i<=k;i++)
for(int j=;j<=k;j++) r[i][j]=rdn();
for(int i=;i<=n;i++)
for(int j=;j<=k;j++)
if(t[i][j]<=lm)add(i,j);
for(int i=;i<=n;i++)
{
memset(vis,,sizeof vis);
xyl(i);
}
for(int i=;i<=k;i++)
if(per[i])prn[per[i]]=i;
for(int i=;i<=n;i++)printf("%d ",prn[i]);puts("");
return ;
}

剩下 op=1 的点,试图用模拟退火,但效果很不好,几乎没有什么改变。自己不是很了解随机化算法……

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cmath>
#define db double
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mx(int a,int b){return a>b?a:b;}
int Mn(int a,int b){return a<b?a:b;}
const int N=,M=,K=;
const db dec=0.988,eps=1e-;
int n,m,k,op,prn[N],a[N],b[N];
int t[N][K],r[K][K],ans;
struct Ed{
int x,y;
}ed[M];
int cal(bool fx)
{
int ret=;
for(int i=;i<=n;i++)
ret+=t[i][fx?b[i]:a[i]];
for(int i=;i<=m;i++)
{
int u=ed[i].x,v=ed[i].y;
ret+=t[fx?b[u]:a[u]][fx?b[v]:a[v]];
}
return ret;
}
int get_rd(db T)
{
ll ret=(rand()*-RAND_MAX)*T;
return ret%k;
}
void SA(db T)
{
int ys=cal(),ts; int deb=;
while(T>eps)
{
int p=rand()%n+,d=a[p]+get_rd(T), cnt=;
while(d==a[p]&&cnt<)d=a[p]+get_rd(T),cnt++;
d=Mx(d,); d=Mn(d,k); b[p]=d;
ts=cal();
if(ts<ys||exp((ts-ys)/T)*RAND_MAX<rand())
{
a[p]=d; ys=ts;
if(ts<ans)memcpy(prn,a,sizeof a);
}
b[p]=a[p]; T*=dec;
}
}
int main()
{
srand(time());
n=rdn();m=rdn();k=rdn();op=rdn();
for(int i=;i<=m;i++)
{ ed[i].x=rdn();ed[i].y=rdn();}
for(int i=;i<=n;i++)
for(int j=;j<=k;j++) t[i][j]=rdn();
for(int i=;i<=k;i++)
for(int j=;j<=k;j++) r[i][j]=rdn();
for(int i=;i<=n;i++)a[i]=b[i]=prn[i]=rand()%k+;
ans=cal();
for(int i=;i<=;i++)
SA();
for(int i=;i<=n;i++)printf("%d ",prn[i]);puts("");
return ;
}

LOJ 2557 「CTSC2018」组合数问题 (46分)的更多相关文章

  1. LOJ2557. 「CTSC2018」组合数问题

    LOJ2557. 「CTSC2018」组合数问题 这道题是我第一道自己做完的题答题.考场上面我只拿了41分,完全没有经验.现在才发现其实掌握了大概的思路还是不难. 首先模拟退火,通过了1,2,6,9, ...

  2. loj#2552. 「CTSC2018」假面

    题目链接 loj#2552. 「CTSC2018」假面 题解 本题严谨的证明了我菜的本质 对于砍人的操作好做找龙哥就好了,blood很少,每次暴力维护一下 对于操作1 设\(a_i\)为第i个人存活的 ...

  3. Loj #2554. 「CTSC2018」青蕈领主

    Loj #2554. 「CTSC2018」青蕈领主 题目描述 "也许,我的生命也已经如同风中残烛了吧."小绿如是说. 小绿同学因为微积分这门课,对"连续"这一概 ...

  4. Loj #2553. 「CTSC2018」暴力写挂

    Loj #2553. 「CTSC2018」暴力写挂 题目描述 temporaryDO 是一个很菜的 OIer .在 4 月,他在省队选拔赛的考场上见到了<林克卡特树>一题,其中 \(k = ...

  5. loj #2143. 「SHOI2017」组合数问题

    #2143. 「SHOI2017」组合数问题   题目描述 组合数 Cnm\mathrm{C}_n^mC​n​m​​ 表示的是从 nnn 个互不相同的物品中选出 mmm 个物品的方案数.举个例子, 从 ...

  6. LOJ 2553 「CTSC2018」暴力写挂——边分治+虚树

    题目:https://loj.ac/problem/2553 第一棵树上的贡献就是链并,转化成 ( dep[ x ] + dep[ y ] + dis( x, y ) ) / 2 ,就可以在第一棵树上 ...

  7. LOJ 2555 「CTSC2018」混合果汁——主席树

    题目:https://loj.ac/problem/2555 二分答案,在可以选的果汁中,从价格最小的开始选. 按价格排序,每次可以选的就是一个前缀.对序列建主席树,以价格为角标,维护体积和.体积*价 ...

  8. LOJ 2554 「CTSC2018」青蕈领主——结论(思路)+分治FFT

    题目:https://loj.ac/problem/2554 一个“连续”的区间必然是一个排列.所有 r 不同的.len 最长的“连续”区间只有包含.相离,不会相交,不然整个是一个“连续”区间. 只有 ...

  9. LOJ 2552 「CTSC2018」假面——DP

    题目:https://loj.ac/problem/2552 70 分就是 f[i][j] 表示第 i 个人血量为 j 的概率.这部分是 O( n*Q ) 的:g[i][j][0/1] 表示询问的人中 ...

随机推荐

  1. PHP批量生成底部带编号二维码(二维码生成+文字生成图片+图片拼接合并)

    PHP批量生成带底部编号二维码(二维码生成+文字生成图片+图片拼接合并) 需求: 输入编号如 : cb05-0000001  至 cb05-0000500 批量生成 以编号为名称的下图二维码,然后压缩 ...

  2. Using Tensorflow SavedModel Format to Save and Do Predictions

    We are now trying to deploy our Deep Learning model onto Google Cloud. It is required to use Google ...

  3. java 工厂模式 从无到有-到简单工厂模式-到工厂方法模式-抽象工厂模式

    工厂模式定义(百度百科): 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式.著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见.因为工 ...

  4. Interface-接口的实现与注意事项

    package cn.learn.Interface; public interface MyInterfaceA { public abstract void methodA(); public a ...

  5. [BZOJ3622] 已经没有什么好害怕的了(dp+容斥)

    Description: ​ 有两个数组a和b,两两配对,求 \(a_i>b_i\) 的配对比 \(b_i>a_i\) 的配对多 \(k\) 个的方案数 \(k\le n\le 2000\ ...

  6. Notepad++添加插件Funtion List 支持PHP

    插件下载地址:functionlist插件 配置方法:关闭notepad++; functionlist.dll拷贝到 安装目录/plugins目录下; 下载php.bmp 地址:https://gi ...

  7. JavaScript给动态插入的元素添加事件绑定

    由于实际的需要,有时需要往网页中动态的插入HTML内容,并在插入的节点中绑定事件处理函数.我们知道,用Javascript向HTML文档中 插入内容,有两种方法, 一种是在写HTML代码写入JS,然后 ...

  8. python 从csv文件插入mysql数据库

    一个工作遇到的问题,将excel文件的内容插入到mysql数据库中. 总体思路是 excel文件-->转换成csv文件-->csv文件读取-->读取数据插入mysql数据库 用到py ...

  9. MySQL语句优化方法(简单版)

    基础回顾: sql语句是怎么样运行的? 一般来说,客户端发送sql语句到数据库服务器——数据库服务器进行运算并返回结果——客户端显示sql语句运行结果. 在本地运行时以workbench为例,客户端为 ...

  10. 三 Bash Shell 结构

    Bash Shell 程序结构主要有 : 变量设定  内置命令 Shell 语法结构 函数 其他命令行程序构成 例子: [root@localhost ~]# vim test.sh #!/bin/b ...