POJ1180 Batch Scheduling
Description
There is a sequence of N jobs to be processed on one machine. The jobs are numbered from 1 to N, so that the sequence is 1,2,..., N. The sequence of jobs must be partitioned into one or more batches, where each batch consists of consecutive jobs in the sequence. The processing starts at time 0. The batches are handled one by one starting from the first batch as follows. If a batch b contains jobs with smaller numbers than batch c, then batch b is handled before batch c. The jobs in a batch are processed successively on the machine. Immediately after all the jobs in a batch are processed, the machine outputs the results of all the jobs in that batch. The output time of a job j is the time when the batch containing j finishes.
A setup time S is needed to set up the machine for each batch. For each job i, we know its cost factor Fi and the time Ti required to process it. If a batch contains the jobs x, x+1,... , x+k, and starts at time t, then the output time of every job in that batch is t + S + (Tx + Tx+1 + ... + Tx+k). Note that the machine outputs the results of all jobs in a batch at the same time. If the output time of job i is Oi, its cost is Oi * Fi. For example, assume that there are 5 jobs, the setup time S = 1, (T1, T2, T3, T4, T5) = (1, 3, 4, 2, 1), and (F1, F2, F3, F4, F5) = (3, 2, 3, 3, 4). If the jobs are partitioned into three batches {1, 2}, {3}, {4, 5}, then the output times (O1, O2, O3, O4, O5) = (5, 5, 10, 14, 14) and the costs of the jobs are (15, 10, 30, 42, 56), respectively. The total cost for a partitioning is the sum of the costs of all jobs. The total cost for the example partitioning above is 153.
You are to write a program which, given the batch setup time and a sequence of jobs with their processing times and cost factors, computes the minimum possible total cost.
program poj1180; const maxn=10010; var i,head,tail,n,s:longint; opt,dp,f,t:array[-1..maxn]of int64; function g(x,y:longint):extended; begin exit((dp[x]-dp[y])/(t[x]-t[y])); end; begin readln(n); readln(s); for i:=1 to n do readln(t[i],f[i]); for i:=n-1 downto 1 do begin inc(t[i],t[i+1]); inc(f[i],f[i+1]); end; t[n+1]:=0;f[n+1]:=0; head:=1;tail:=1;opt[1]:=n+1;dp[n+1]:=0; for i:=n downto 1 do begin while (head<tail)and(g(opt[head+1],opt[head])<f[i]) do inc(head); dp[i]:=dp[opt[head]]+(s+t[i]-t[opt[head]])*f[i]; while (head<tail)and(g(opt[tail],opt[tail-1])>g(i,opt[tail])) do dec(tail); inc(tail);opt[tail]:=i; end; writeln(dp[1]); end.
POJ3709 K-Anonymous Sequence
Description
The explosively increasing network data in various application domains has raised privacy concerns for the individuals involved. Recent studies show that simply removing the identities of nodes before publishing the graph/social network data does not guarantee privacy. The structure of the graph itself, along with its basic form the degree of nodes, can reveal the identities of individuals.
To address this issue, we study a specific graph-anonymization problem. We call a graph k-anonymous if for every node v, there exist at least k-1 other nodes in the graph with the same degree asv. And we are interested in achieving k-anonymous on a graph with the minimum number of graph-modification operations.
We simplify the problem. Pick n nodes out of the entire graph G and list their degrees in ascending order. We define a sequence k-anonymous if for every element s, there exist at least k-1 other elements in the sequence equal to s. To let the given sequence k-anonymous, you could do one operation only—decrease some of the numbers in the sequence. And we define the cost of the modification the sum of the difference of all numbers you modified. e.g. sequence 2, 2, 3, 4, 4, 5, 5, with k=3, can be modified to 2, 2, 2, 4, 4, 4, 4, which satisfy 3-anonymous property and the cost of the modification will be |3-2| + |5-4| + |5-4| = 3.Give a sequence with n numbers in ascending order and k, we want to know the modification with minimal cost among all modifications which adjust the sequence k-anonymous.
也是一道斜率优化的拓展题。首先我们可以非常熟练地推出斜率:
g[j,k]=(f[j]-s[j]+j*a[j]-(f[k]-s[k]+k*a[k]))/(a[j]-a[k])
推的过程大同小异这里就不详细列出了。
然后转移方程
f[i]=f[j]+s[i]-s[j]-(i-j)*a[j]
(a[j]=s[j+1])(为了形式更优美我们把下标换成j当然不换也没有什么关系)
这道题的问题有两个
其中一个是k要怎么控制?刚开始想了一个并不好的方法就是在求解的时候各种控制但是还要担心缩tail的时候会影响后面的答案...
其实只要从DP的角度考虑,将i点加入队列无非就是给i以后的点增加一个可转移的状态
那么只要保证当前在求i的时候,i-k+1..i-1的点不在单调队列里就行了
自然而然地想到了延迟入队这样问题就迎刃而解了
在上一道题中,保证每个零件的加工时间都是非负整数,因此表示前缀和的t数组数字各不相同
而这道题不一样,作为分母的a数组可能相同,所以斜率还要特判分母等于0的情况
刚开始就是这里出了错。返回值要根据分子的符号来决定是正无穷还是负无穷。
program poj3709; const maxn=500010;INF=1000000000000; var t,test,n,k,head,tail,v,i:longint; s,a,opt,f:array[-1..maxn]of int64; function g(x,y:longint):extended; begin if a[x]<>a[y] then exit((f[x]-s[x]+x*a[x]-f[y]+s[y]-y*a[y])/(a[x]-a[y])); if (f[x]-s[x]+x*a[x]-f[y]+s[y]-y*a[y])>0 then exit(INF) else exit(-INF); //如果分子是正的就返回正无穷否则返回负无穷 end; begin readln(test); for t:=1 to test do begin readln(n,k); for i:=1 to n do read(s[i]);s[n+1]:=0; for i:=0 to n do a[i]:=s[i+1]; for i:=2 to n do inc(s[i],s[i-1]); head:=1;tail:=1;opt[1]:=0;s[0]:=0;f[0]:=0; for i:=k to n do //这里我控制的目的是不要让<k的无用状态将head移向后面 begin while (head<tail)and(g(opt[head+1],opt[head])<i) do inc(head); f[i]:=f[opt[head]]+(s[i]-s[opt[head]])-(i-opt[head])*a[opt[head]]; if i-k+1>=k then //为下一次作的准备,i+1的时候需要i+1-k的状态。而且显然<k的状态是不能被转移的 begin while (head<tail)and(g(opt[tail],opt[tail-1])>g(i-k+1,opt[tail])) do dec(tail); inc(tail);opt[tail]:=i-k+1; end; end; writeln(f[n]); end; end.