Descripción
Thank to
cryptography, we are able to encrypt messages such that none (except the
intended recipient) is able to read them. However, encrypted messages
are of no use if they do not actually reach
the recipient. These days, computer network is the most typical mean to
send such messages. In this problem, we will study the issues the
networking providers have to solve. And remember: since the message is
encrypted, we do not need to care about the network privacy anymore.
The network cables joining computers (servers) belong to different companies. A new anti-monopoly legislation prevents any company from owning more than two cables from each server. Furthermore, to avoid wasting resources, there is also a law specifying that the cable system owned by any single company cannot be redundant, i.e., removal of any of the cables will disconnect some two previously connected servers. Since the companies buy and sell the cables all the time, it is quite difficult to enforce these regulations. Your task is to write a program that does so.
The network cables joining computers (servers) belong to different companies. A new anti-monopoly legislation prevents any company from owning more than two cables from each server. Furthermore, to avoid wasting resources, there is also a law specifying that the cable system owned by any single company cannot be redundant, i.e., removal of any of the cables will disconnect some two previously connected servers. Since the companies buy and sell the cables all the time, it is quite difficult to enforce these regulations. Your task is to write a program that does so.
Especificación de entrada
The input
contains several instances. The first line of each instance contains
four integers N, M, C and T separated by spaces - the number of servers
(1 <= N <= 8000), the number of cables (0 <= M <= 10^5), the
number of companies (1 <= C <= 10^2), and the number of
cable-selling transactions (0 <= T <= 10^5), respectively.
The following M lines describe the cables. Each of them contains three integers Sj1 , Sj2 and Kj , separated by spaces, giving the numbers of the servers Sj1 and Sj2 (1 <= Sj1 < Sj2 <= N) joined by that cable and the number of the company Kj (1 <= Kj <= C) initially owning the cable. For each pair of servers, there is at most one cable joining them. The initial state satisfies the regulations, i.e., each company owns at most two cables incident with each server, and the system of cables owned by a single company has no cycles.
Finally, each of the next T lines contains integers Si1 , Si2 and Ki describing one transaction in which the company Ki (1 <= Ki <= C) tries to buy a cable between servers Si1 and Si2 (1 <= Si1 < Si2 <= N).
The last instance is followed by a line containing four zeros.
The following M lines describe the cables. Each of them contains three integers Sj1 , Sj2 and Kj , separated by spaces, giving the numbers of the servers Sj1 and Sj2 (1 <= Sj1 < Sj2 <= N) joined by that cable and the number of the company Kj (1 <= Kj <= C) initially owning the cable. For each pair of servers, there is at most one cable joining them. The initial state satisfies the regulations, i.e., each company owns at most two cables incident with each server, and the system of cables owned by a single company has no cycles.
Finally, each of the next T lines contains integers Si1 , Si2 and Ki describing one transaction in which the company Ki (1 <= Ki <= C) tries to buy a cable between servers Si1 and Si2 (1 <= Si1 < Si2 <= N).
The last instance is followed by a line containing four zeros.
Especificación de salida
For each input instance, output T lines describing the outcome of the transactions. The possible outcomes are:
- "No such cable." if the pair of servers is not joined by a cable,
- "Already owned." if the cable is already owned by the company Ki,
- "Forbidden: monopoly." if the company Ki already owns two cables at Si1 or Si2,
- "Forbidden: redundant." if Ki owns at most one cable at each of Si1 and Si2, but granting the ownership would create a cycle of cables owned by Ki,
- "Sold." if none of the above restrictions apply. In this case, the ownership of the cable between Si1 and Si2 changes to Ki for the purpose of further transactions.
- Print one empty line after each instance.
Ejemplo de entrada
4 5 3 5 1 2 1 2 3 1 3 4 2 1 4 2 1 3 3 1 2 3 1 2 3 1 4 3 2 3 3 2 4 3 2 1 1 1 1 2 1 1 2 1 0 0 0 0
Ejemplo de salida
Sold. Already owned. Forbidden: monopoly. Forbidden: redundant. No such cable. Already owned.
Sugerencia(s)
| Origen | 2010/2011 ACM-ICPC Central Europe Regional Contest |
| Adicionado por | ymondelo20 |
| Fecha de adición | 2012-04-22 |
| Tiempo límite (ms) | 10000 |
| Memoria límite (kb) | 130000 |
| Salida límite (mb) | 64 |
| Tamaño límite (bytes) | 30000 |
| Languages activados | C C# C++ Java Pascal Perl PHP Python Ruby Text |
Vaya, es un problema complicado... Hasta el momento en que escribo esto solo dos personas lo han resuelto en la página. Creo que el principal problema es cómo averiguar rápidamente si se forman ciclos en un grafo, del cual vamos a estar borrando y agregando aristas repetidamente. Vayan buscando información sobre algoritmos para encontrar ciclos rápidamente en grafos... Por la cantidad de vértices, difícilmente usaremos una representación matricial, la opción será usar listas enlazadas. No olviden que el problema tiene límite de memoria de 130 MB y 10 segundos en tiempo de ejecución. Bueno, pues a trabajar. Publiquen sus avances, dudas, comentarios, sugerencias, lo que sea...
ResponderEliminarHoy sábado 12 de mayo estuvimos en el curso debatiendo diversas posibilidades para intentar resolver el problema. Después de un par de horas llegamos a una solución. Tras corregir algunos errores mi código seguía sin ser aceptado en la COJ. Estuve revisándolo bastante tiempo sin encontrar errores, y es que el problema es que me marcaba Time Limited Exceeded. Pensé en buscarlo en otras páginas para probarlo. Como es un problema de un Regional del ACM ICPC pensé en entrar al ACM ICPC Live Archive, donde uno puede subir sus codigos para cualquier Regional y Final del mundo del ACM ICPC. Me llevé una sorpresa al ver que ahí sí me aceptaron mi código. ¿A qué se debe esto? Aún no lo sé. Es posible que en la COJ sea necesario un código más eficiente. También podría haber un error en la COJ en la evaluación del problema, es raro que solo una persona lo haya resuelto... No lo sé. En el ACM ICPC Live Archive me lo aceptaron pero corriendo justo de tiempo. Dejo mi codigo a continuación con algunos comentarios. Publiquen cualquier duda, comentario sugerencia o código.
ResponderEliminar#include<stdio.h>
ResponderEliminarlong n,m,c,t,i,j,k,x,y,z,v,ini,l[2][100002],b;
char g[8002][8002];
bool r;
struct ciclos{
long u[8002]; // u de uno
long d[8002]; // d de dos
}a[101];
void dfs(long se,long de){ // se de servidor de de donde viene
// Esta funcion recorre la trayectoria en busca de un ciclo
if(se==ini){ // Despues observe que podia hacerse esto con un simple while
r=true;
}else{
if(a[z].u[se]!=de&&a[z].u[se]>0)
dfs(a[z].u[se],se);
if(a[z].d[se]!=de&&a[z].d[se]>0)
dfs(a[z].d[se],se);
}
}
int main(){
scanf("%ld %ld %ld %ld",&n,&m,&c,&t);
while(n+m+c+t>0){
b=m; // Esta funcion sera para despues limpiar lo necesario
// No olvidemos que es un problema multicasos
for(i=0;i<m;i++){
scanf("%ld %ld %ld",&x,&y,&z);
l[0][i]=x;
l[1][i]=y;
g[x][y]=z;
g[y][x]=z;
if(a[z].u[x]==0)
a[z].u[x]=y;
else
a[z].d[x]=y;
if(a[z].u[y]==0)
a[z].u[y]=x;
else
a[z].d[y]=x;
}
for(i=0;i<t;i++){
scanf("%ld %ld %ld",&x,&y,&z);
if(g[x][y]==0){
printf("No such cable.\n");
}else if(g[x][y]==z){
printf("Already owned.\n");
}else if(a[z].d[x]>0||a[z].d[y]>0){
printf("Forbidden: monopoly.\n");
}else{
if(a[z].u[x]==0||a[z].u[y]==0){ // Uno de los nodos no tenia aristas, entonces no puede haber ciclo
// Lo borramos de la otra empresa
v=g[x][y];
if(a[v].d[x]==y){
a[v].d[x]=0;
}else{
a[v].u[x]=a[v].d[x];
a[v].d[x]=0;
}
if(a[v].d[y]==x){
a[v].d[y]=0;
}else{
a[v].u[y]=a[v].d[y];
a[v].d[y]=0;
}
// Lo agregamos a la nueva empresa
g[x][y]=z;
g[y][x]=z;
if(a[z].u[x]==0)
a[z].u[x]=y;
else
a[z].d[x]=y;
if(a[z].u[y]==0)
a[z].u[y]=x;
else
a[z].d[y]=x;
printf("Sold.\n");
}else{
// Busquemos ciclos Ponemos la arista
a[z].d[x]=y; // Para entrar aqui ninguno de los nodos era nuevo
a[z].d[y]=x;
ini=x;
r=false;
dfs(a[z].u[x],ini);
if(r){ // Esto implica ciclo
// Borramos la arista
a[z].d[x]=0;
a[z].d[y]=0;
printf("Forbidden: redundant.\n");
}else{ // Entonces si se vende
// Borramos la arista de la otra K y cambiamos el g
v=g[x][y];
if(a[v].d[x]==y){
a[v].d[x]=0;
}else{
a[v].u[x]=a[v].d[x];
a[v].d[x]=0;
}
if(a[v].d[y]==x){
a[v].d[y]=0;
}else{
a[v].u[y]=a[v].d[y];
a[v].d[y]=0;
}
g[x][y]=z;
g[y][x]=z;
printf("Sold.\n");
}
}
}
}
printf("\n");
scanf("%ld %ld %ld %ld",&n,&m,&c,&t);
if(n+m+c+t>0) // Aqui limpiamos lo necesario para recibir al siguiente caso
for(i=0;i<b;i++){
x=l[0][i];
y=l[1][i];
z=g[x][y];
g[x][y]=0;
a[z].u[x]=0;
a[z].d[x]=0;
a[z].u[y]=0;
a[z].d[y]=0;
}
}
}
A mi no me aceptaron mi codigo por limite de tiempo. Por lo menos funciona con el caso prueba.
ResponderEliminar#include
long s,ca,n,co, t,s1,s2,k,compaia,v1,v2,a[8001][2001],i,j;
int main(){
scanf("%ld %ld %ld %ld",&s,&ca,&co,&t);
while(s+ca+co+t>0){
for(i=1;i<ca+1;i++){
scanf("%ld %ld %ld",&s1,&s2,&k);
if(a[s1][2*k-1]==0){
a[s1][2*k-1]=s2;
}else{
a[s1][2*k]=s2;
}
if(a[s2][2*k-1]==0){
a[s2][2*k-1]=s1;
}else{
a[s2][2*k]=s1;
}
}
for(n=1;n<t+1;n++){
compaia=0;
scanf("%ld %ld %ld",&s1,&s2,&k);
for(i=1;i<2*co+1;i++){
if(a[s1][i]==s2){
compaia=(i+1)/2;
break;
}
}
if(compaia==0){
printf("No such cable.\n");
continue;
}
if(compaia==k){
printf("Already owned.\n");
continue;
}
if(a[s1][2*k]!=0||a[s2][2*k]!=0){
printf("Forbidden: monopoly.\n");
continue;
}
v1=s1;
v2=9000;
while(v1!=s2&&v1!=0){
if(a[v1][2*k-1]!=v2){
v2=v1;
v1=a[v1][2*k-1];
}else{
v2=v1;
v1=a[v1][2*k];
}
}
if(v1==s2){
printf("Forbidden: redundat.\n");
continue;
}else{
printf("Sold.\n");
if(a[s1][2*k-1]==0){
a[s1][2*k-1]=s2;
}else{
a[s1][2*k]=s2;
}
if(a[s2][2*k-1]==0){
a[s2][2*k-1]=s1;
}else{
a[s2][2*k]=s1;
}
if(a[s1][2*compaia-1]==s2){
a[s1][2*compaia-1]=a[s1][2*compaia];
a[s1][2*compaia]=0;
}else{
a[s1][2*compaia]=0;
}
if(a[s2][2*compaia-1]==s1){
a[s2][2*compaia-1]=a[s2][2*compaia];
a[s2][2*compaia]=0;
}else{
a[s2][2*compaia]=0;
}
}
}
for(i=1;i<s+1;i++){
for(j=1;j<2*co+1;j++)
a[i][j]=0;
}
printf("\n");
scanf("%ld %ld %ld %ld",&s,&ca,&co,&t);
}
}
En general es mas rapido hacer funciones y despues utilizarlas?, o escribir directamente en el codigo lo que queremos hacer?
ResponderEliminarTengo entendido que no hay gran diferencia, aunque creo que es un poco mejor escribir directamente en el código. ¿Probaste envíandolo en el ACM ICPC Live Archive? En esa página el problema tiene ID 5884.
ResponderEliminarSi, lo envie en ambas paginas, y en las dos me marcaba limite de tiempo excedido.
ResponderEliminar